Language/Python

파이썬 - 함수와 모듈

728x90
반응형

 

 

어느 정도 규모의 프로그램을 개발하다 보면 중복으로 사용되는 코드가 생기는데, 이럴 때 보통 프로그래밍 경험이 많지 않은 초보자들은 이전에 작성된 코드를 단순히 복사한 후 붙여넣어서 프로그램을 작성하곤 한다. 그러나 이런 식으로 프로그램을 작성하게 되면 점점 코드의 유지 보수가 어려워진다.

 

예를 들어, 어느 날 이전에 작성한 코드에 문제가 있다는 사실을 알게 되어 해당 문제를 수정한다고 하더라도 이미 해당 코드는 프로그램의 여러 곳에서 복사되어 사용되고 있을 수 있다. 이 경우 해당 코드를 하나도 빠짐없이 찾아서 제대로 수정해야 하는데, 생각만 해도 끔찍한 일이다.

 

이러한 문제를 막고자 중복 코드를 재사용하고 싶을 때는 단순히 코드를 복사해서 붙여넣는 식으로 프로그램을 작성하는 것이 아니라 함수(function)라고 하는 형태로 코드를 작성하는 것이 좋다. 함수라는 것은 한번 잘 작성해두면 두고두고 이를 '호출'해서 사용할 수 있으므로 개발 생산성을 크게 높일 수 있다.

 

파이썬에서 화면에 값을 출력할 때 사용했던 print()라는 함수는 사용자가 직접 구현하지 않았음에도 print() 함수를 호출해서 사용했던 것을 생각해보면 함수가 얼마나 유용한지 알 수 있다.

 

파이썬의 모듈(module)은 함수보다 더 큰 단위의 코드 묶음을 의미한다.

보통 함수가 수십 줄 내의 코드로 구성된다면 파이썬의 모듈은 파일 단위의 코드 묶음을 의미한다.

 

 

1. 함수(Function)

 

 

 

 

위의 박스는 어느 수를 넣으면 그 수의 절댓값을 돌려주는 기능을 한다.

파이썬의 함수도 위에 나와 있는 박스와 비슷하며 특정한 기능을 수행하는 코드의 집합이고, 쉽게 말하면 여러 문장을 하나로 묶는 기능을 한다.

 

파이썬 내에서 함수를 정의하는 방법은 다음과 같다.

파이썬에서 함수를 만들기 위해서는 줄의 맨 앞에 def라는 키워드로 시작하고

함수명과 괄호를 열고 닫은 후 콜론을 입력한다.

함수의 몸체를 구성하는 코드는 들여쓰기를 해야 한다.

또한, 함수가 하나 이상의 값을 반환해야 한다면 return이라는 키워드를 입력하여 함수를 호출한 프로그램에 결과물을 반환한다.

 

 

 

위에서는 인자가 보조변수 같은 개념이며, 함수에 필요한 값을 저장해두는 임시 변수이고 인자가 아예 존재하지 않을 수도 있고, 여러 개가 존재할 수도 있다.

 

변수명을 적절히 지정해야 하는 것처럼 def 키워드 다음에는 함수의 기능과 연관된 적당한 함수명을 지정해야 한다.

 

def multi_times():

print("우리증권")

 

 

함수명('multi_times') 다음에는 함수의 입력 값을 넣을 괄호가 나오는데, 입력 값이 없으므로 괄호 안에 아무 값도 없다. 함수의 몸통 즉, 함수의 구현 부분을 살펴보면 화면에 '우리증권'을 출력하기 위한 print 문이 있다. 파이썬에서 함수를 정의할 때도 분기문, 반복문처럼 키워드가 있는 줄의 끝에 콜론(:)이 있고, 실행될 코드 블록은 들여쓰기돼 있어야 한다.

 

 

def multi_times(n):

print("우리증권")

 

출력 횟수를 의미하는 n 변수를 함수의 입력으로 받는 코드이다. n과 같이 함수에 어떤 값을 넘겨줄 때 사용하는 변수를 함수 파라미터 또는 함수 인자라고 한다.

 

만들어진 함수를 호출하는 방법은 파이썬에서 기본적으로 제공하는 print 함수를 사용할 때 print("hello")처럼 함수명을 입력했던 것처럼 함수를 호출하려면 만든 함수의 이름을 파이썬 프롬프트에 입력하면 된다. , print_ntimes()가 아니라 print_ntimes(3)처럼 괄호 안에 값을 하나 넣어야 한다.

 

multi_times(3)

대신증권

>>> multi_times(2)

대신증권

 

위 코드를 보면 뭔가 제대로 동작하지 않는 것을 바로 알 수 있다. 함수를 호출할 때 함수의 인자 값으로 출력 횟수를 입력했지만(각각 32) 입력된 출력 횟수와는 상관없이 '대신증권'이라는 문자열은 항상 한 번만 출력된다. 이는 다음처럼 함수의 입력 값인 n 값과 상관없이 함수 본체에서는 항상 한 번만 출력하도록 구현했기 때문이다.

 

 

 

 

함수의 입력 값인 n만큼 문자열이 출력되게 하려면 함수 내에서 for 문을 사용하면 된다. forrange()를 사용하여 반복문을 만들고 반복문에서 수행할 문장에 print("대신증권")을 적어주면 된다. for 문을 3번 반복하게 하려면 range(3)을 사용하면 되는데 print_ntimes 함수에서는 함수 인자 n을 통해 반복 횟수가 입력되므로 함수 인자인 n만큼 반복 하려면 range(n)을 사용하면 된다.

 

 

>>> def print_ntimes(n):

for i in range(n):

print("대신증권")

 

다음과 같이 함수를 호출해보면 지정한 횟수만큼 반복 처리된다.

 

>>> print_ntimes(1)

대신증권

>>> print_ntimes(2)

대신증권

대신증권

>>> print_ntimes(3)

대신증권

대신증권

대신증권

 

 

다음 예제에서는 정의한 함수를 통해 두 수를 더한 결과를 돌려준다.

 

>>> def total(a, b):

return a + b

>>> total(1, 5)

6

>>> total(100, 20000)

20100

 

위 예제에서는 total이란 이름을 지니고 인자 2개를 가지는 함수를 정의하고, 이 함수는 넘겨받은 두 인자의 값을 서로 더해 돌려주는 기능을 한다.

 

 

[함수 호출의 3단계]

 

 

1) 함수 호출 과정

파이썬에서 def 키워드를 통해 함수를 정의하는 것은 말 그대로 함수를 정의하는 것이며, 함수가 정의됐다고 해서 함수가 실행되는 것은 아니다. 함수가 실행되려면 함수를 호출해야 한다.

 

1단계

파이썬에서 함수를 호출하면 함수의 인자에 위치하는 변수(price)가 함수 호출 시 입력된 인자 값(10000)을 바인딩하게 된다. 함수 호출 시 입력된 인자 값(10000)은 컴퓨터 메모리의 어딘가에 할당되는데, 여기까지가 함수 호출 단계메모리 상태이다.

 

2단계

함수 실행 단계로 이 단계에서는 함수의 수행할 문장이 실행된다. cal_upper 함수에서 수행할 문장은 다음과 같다.

 

increment = price * 0.3

upper_price = price + increment

 

먼저 첫 번째 문장이 실행되고 이에 따라 price * 0.3의 결과값이 메모리의 어딘가에 할당되고 increment 변수는 이 할당된 값을 바인딩한다. 여기서 중요한 것은 price * 0.3이라는 연산의 결과값이 메모리의 어딘가에 실제로 위치한다는 점이다. 그다음 위의 코드에서 두 번째 문장이 실행되고 이에 따라 price + increment의 결과값이 메모리의 어딘가에 할당되고, 그 값을 upper_price 변수가 바인딩하게 된다.

코드가 여기까지 수행됐을 때 price, increment, upper_price 변수가 바인딩하는 값이 실제로 메모리에 저장되어 있다.

 

3단계

함수 종료 단계로 파이썬에서는 메모리 관리 문제를 해결하기 위해 할당된 메모리를 자동으로 관리하는 메커니즘을 사용한다.

, 함수 호출 과정에서 할당된 메모리는 함수 호출이 끝나 더는 사용되지 않을 때 자동으로 메모리에서 삭제된다.

 

함수 호출의 3단계를 코드로 나타내면 다음과 같다.

 

 

 

 

파이썬에서 함수가 호출되면 함수가 정의된 곳으로 가서 메모리를 할당하면서 코드가 실행되고 함수 내부의 수행할 문장에 대한 실행이 완료되면 위 그림의 번처럼 다시 함수가 호출된 곳으로 되돌아간다. 그림의 번 과정에서는 이미 함수의 호출이 종료됐기 때문에 함수 내에서 사용된 모든 메모리는 해제됐고 따라서 함수 내부의 변수를 참조할 수도 없다.

 

정의되지 않았다(not defined)"라는 오류 메시지가 출력되는 것은 함수의 호출이 종료됐기 때문에 함수 내에서 사용된 모든 메모리는 해제됐고 따라서 함수 내부의 변수를 참조할 수도 없기 때문이다.

 

또한, 파이썬은 함수 내부에서 계산된 값을 함수 외부로(함수를 호출한 곳으로) 보내기 위해 return이라는 키워드를 사용한다.

 

다음 코드는 수정된 cal_upper 함수 및 함수의 호출 결과이다. 수정되기 전의 코드와 비교하면 함수의 끝 부분에 함수 내에서 계산된 값인 upper_price를 반환하는 코드가 있음을 알 수 있다. 이처럼 함수에서 계산된 값은 항상 반환해야(돌려줘야) 함수를 호출한 부분에서 그 값을 사용할 수 있다.

 

 

 

 

 

2) 파이썬 내장 함수

파이썬은 자주 사용되는 함수를 내장 함수(Built-in Functions)라는 이름으로 기본적으로 제공한다.

 

예를 들어, 절대값을 구하거나 원소의 개수를 세는 것과 같은 함수가 내장 함수에 해당한다. 다음은 파이썬이 제공하는 내장 함수의 목록이다.

 

 

 

 

abs(x) 내장 함수는 정수형 또는 실수형 값을 입력받은 후 해당 값의 절대값을 반환하는 함수이다.

다음과 같이 내장 함수의 인자로 음수 값을 입력했을 때 입력 값의 절댓값이 반환되는 것을 확인할 수 있다. 다만 정수형 또는 실수형이 아닌 문자열 값이 입력되면 오류가 발생한다.

 

>>> abs(-3)

3

>>> abs(-3.0)

3.0

>>>

>>> abs("hello")

Traceback (most recent call last):

File "<pyshell#8>", line 1, in <module>

abs("hello")

TypeError: bad operand type for abs(): 'str'

>>>

 

chr(i) 내장 함수는 유니코드 값을 입력받은 후 해당 값에 해당하는 문자열을 반환한다.

예를 들어, 아스키(ASCII) 코드에서 알파벳 대문자 A65, 소문자 a97에 해당하는데, 해당하는 정수값을 chr() 함수의 인자로 전달하면 문자열이 반환되는 것을 확인할 수 있다.

 

>>> chr(97)

'a'

>>> chr(65)

'A'

>>>

 

enumerate() 내장 함수는 입력으로 시퀀스 자료형(리스트, 튜플, 문자열) 등을 입력받은 후 enumerate 객체를 반환한다.

enumerate() 내장 함수는 다음과 같이 for 문에서 시퀀스 자료형 내의 값과 인덱스를 동시에 구하고 싶을 때 자주 사용된다.

 

>>> for i, stock in enumerate(['Naver', 'KAKAO', 'SK']):

print(i, stock)

 

0 Naver

1 KAKAO

2 SK

>>>

 

다음 코드는 enumerate() 내장 함수를 사용하지 않고 위의 코드를 다시 구현한 것이다. 이 경우 시퀀스 자료형인 리스트는 따로 인덱스를 갖고 있지 않으므로 i라는 변수를 통해 따로 인덱스값을 계산해야 하는 번거로움이 있다.

 

>>> i = 0

>>> for stock in ['Naver', 'KAKAO', 'SK']:

print(i, stock)

i += 1

 

0 Naver

1 KAKAO

2 SK

>>>

 

id(object) 내장 함수는 객체를 입력받아 해당 객체의 고윳값을 반환한다. 고유값은 파이썬 인터프리터의 구현 방식에 따라 다르지만 보통 객체가 할당된 메모리의 주소 값을 의미한다.

 

다음과 같이 a라는 변수와 b라는 변수가 모두 1이라는 값을 바인딩하고 있을 때 ab가 서로 같은 객체를 바인딩하고 있는지 확인하려면 id() 내장 함수의 반환값이 같은지 확인하면 된다.

id() 내장 함수의 반환값이 같은 경우 두 변수는 서로 같은 객체를 바인딩하고 있음을 의미한다.

 

>>> a = 1

>>> b = 1

>>> id(a)

1918947744

>>> id(b)

1918947744

>>>

 

len(s) 내장 함수는 리스트, 튜플, 문자열, 딕셔너리 등을 입력받아 그 객체의 원소 개수를 반환한다.

 

>>> len(['SK', 'naver'])

2

>>> len('SK hynix')

8

>>> len({1:'SK', 2:'Naver'})

2

>>>

 

list() 내장 함수는 문자열이나 튜플을 입력받은 후 리스트 객체로 만들고 해당 리스트를 반환한다.

다음과 같이 튜플을 리스트로 변환할 때 자주 사용된다.

 

>>> list('hello')

['h', 'e', 'l', 'l', 'o']

>>> list((1,2,3))

[1, 2, 3]

>>>

 

max() 내장 함수는 입력값 중 최댓값을 반환한다. 반대로 min() 내장 함수는 입력값 중 최소값을 반환한다.

 

>>> max(1,2,3)

3

>>> max([1,2,3])

3

>>> min(1,2,3)

1

>>> min([1,2,3])

1

>>>

 

sorted() 내장 함수는 입력값을 정렬한 후 정렬된 결과값을 '리스트'로 반환합니다.

 

>>> sorted((4,3,1,0))

[0, 1, 3, 4]

>>> sorted([5, 4, 3, 2, 1])

[1, 2, 3, 4, 5]

>>> sorted(['c', 'b', 'a'])

['a', 'b', 'c']

>>>

 

int(x) 내장 함수는 문자열을 인자로 입력받아 해당 문자열을 정수형으로 변환한 후 반환한다.

반대로 str(x) 내장 함수는 객체를 입력받아 문자열로 변환한다. int(x)str(x) 내장 함수는 다음과 같이 문자열을 정수형으로, 정수형을 문자열로 변환할 때 자주 사용된다.

 

>>> int('3')

3

>>> str(3)

'3'

>>>

 

 

 

 

2. 모듈(module)

파이썬의 모듈은 '프로그램의 기능 단위'를 의미하는데 다만 파이썬은 파일 단위로 작성된 파이썬 코드를 모듈이라고 부른다.

 

, 파이썬에서의 모듈이란 변수, 클래스, 함수 등과 같은 여러 코드를 한곳에 모아놓은 코드의 모음이라고 할 수 있다. 이런 모듈이라는 것을 만들어 놓으면 계속 사용할 수 있으므로 코드의 재사용성을 극대화 시킬 수 있으며, 연관성이 있는 것들을 모듈 단위로 분리하여 효율성을 높일 수 있다.

 

모듈이라는 것을 가져오려면 'import'라는 키워드를 통해 모듈을 다음과 같이 불러올 수 있다.

 

import 모듈명

 

예를 들어,

파이썬에 기본으로 내장된 모듈을 불러와 그 모듈의 기능을 한번 이용해보도록 한다.

math라는 내장 모듈을 불러와서 dir 함수를 아래와 같이 사용해보자.

 

>>> import math

>>> dir(math)

 

 

위와 같이 math라는 내장 모듈을 불러오고 나서, dir 함수를 사용하면 그 모듈 내에 있는 여러 가지 데이터라던지 함수를 알아낼 수 있다.

 

모듈 내에 있는 함수를 사용하려면 '모듈명.함수명'과 같이 사용한다.

 

>>> math.sin(90)

0.8939966636005579

>>> math.pow(2, 10)

1024.0

>>> math.pi

3.141592653589793

>>>

 

함수를 직접 정의하지 않아도 math라는 모듈을 불러와 그 모듈에 있는 함수들을 그대로 사용할 수 있다는 사실을 알 수 있다.

파이썬에서는 이런 수학과 관련된 모듈만이 존재하는 것이 아니라, 시간, 파일 등과 관련된 다양한 모듈이 존재한다. 위와 같이 내장되어 있는 모듈도 있지만, 사용자 직접 모듈을 만들어서 불러와 사용할 수 있다.

 

 

 

 

 

 

위의 그림처럼 stock.py라는 파일에는 두 개의 함수(cal_upper_lower, cal_macd)와 하나의 리스트(mylist)가 있는 것을 볼 수 있다. 여기서 함수 및 리스트를 포함하는 파일의 이름이 stock이므로 파이썬에서는 이 파일을 stock 모듈이라고 부른다. 참고로 마이크로소프트의 워드 파일에 .docx와 같은 확장자가 붙는 것처럼 보통 파이썬 코드는 .py라는 확장자를 사용한다.

 

파이썬에서 모듈을 사용하는 이유는 함수를 사용하는 이유가 코드의 재사용을 위해서인 것과 같이 모듈은 함수보다 상위 개념으로 함수와 마찬가지로 코드의 재사용을 위해 사용한다.

 

예를 들어, 시스템 트레이딩과 관련된 프로그램을 작성할 경우 다른 사람이 작성한 함수를 재사용하고 싶다면, 먼저 함수의 코드를 복사한 후 여러분의 프로그램에 붙여 넣은 다음 함수를 호출해야 한다. 다른 사람이 작성한 함수를 사용하기 위해 함수 코드 전체를 복사한 후 붙여 넣는 작업은 여간 번거로운 작업이 아니며 또한, 시간이 흐른 후에 해당 함수가 업데이트되는 경우를 생각하면 함수가 업데이트될 때마다 코드를 새로 복사한 후 붙여넣기 해줘야 한다.

 

파이썬의 모듈을 사용하는 경우에는 함수가 정의돼 있는 파일 자체를 복사한 후 모듈을 임포트(import)하기만 하면 해당 파일(모듈)에 구현된 모든 함수 및 자료구조를 사용할 수 있다. , 모듈을 사용하면 함수를 사용하기 위해 함수 코드를 코드에 복사 후 붙여 넣는 작업을 하지 않아도 된다.

 

1) 모듈 정의

파이썬의 모듈은 사실 파일(.py)로 저장되어 있으며 위에서 사용한 내장 모듈도 파이썬이 설치되어 있는 디렉터리 내의 lib이라는 디렉터리에서 찾을 수 있다.

 

결론적으로, 파이썬에서 모듈을 정의한다는 것은 파일을 만든다는 의미이다.

우선은 간단하게 사칙연산을 지원하는 모듈을 만들어 보도록 한다.

이 모듈의 이름은 arithmetic으로 하고 윈도우에 기본으로 내장되어 있는 메모장이나 워드패드 등과 같은 텍스트 편집기를 이용해서 모듈을 만들어 본다.

모듈의 확장자는 파이썬 파일과 같이 .py이며 전체적인 파일의 이름은 arithmetic.py가 된다.

 

def plus(a, b):

return a + b

def minus(a, b):

return a - b

def div(a, b):

return a / b

def mul(a, b):

return a * b

 

위와 같이 모듈을 작성한 후 파일을 파이썬이 설치된 디렉터리 내에 있는 라이브러리 디렉터리에 저장한다.(C:\Python33\Lib가 파이썬 라이브러리 디렉터리 경로)

 

이제 IDLE를 실행시켜서 만든 모듈을 불러온다.

 

>>> import arithmetic

>>> dir(arithmetic)

['__builtins__', '__cached__', '__doc__', '__file__', '__initializing__', '__loader__', '__name__', '__package__', 'div', 'minus', 'mul', 'plus']

>>> arithmetic.plus(1, 2)

3

>>> arithmetic.mul(5, 5)

25

 

 

 

 

 

 

위 예제처럼 import라는 키워드를 이용하여 만든 arithmetic이란 모듈을 불러올 수 있다.

기능이 모두 정상적으로 동작하고 있음을 확인할 수 있다. 파이썬에서 모듈을 찾는 순서는 모듈이 이미 로딩되었는지 확인한 뒤에 로딩되어 있지 않다면 파이썬 경로를 탐색하며 여기에도 존재하지 않으면 PYTHONPATH 환경변수에 등록된 경로에 들어가 탐색을 시작한다. 만약 위처럼 모듈명을 같이 적지 않고도 바로 참조를 하려면 다음과 같이 import 구문을 사용하면 된다.

 

>>> from arithmetic import plus

>>> plus(1, 2)

3

>>> plus(123, 456)

579

 

위 예제에서는 'from 모듈명 import 어트리뷰트'와 같은 형식으로 불러오면 해당 어트리뷰트는 모듈명을 적지 않고도 직접 함수를 참조할 수 있다.

여기서 어트리뷰트란 함수나 간단히 변수 등의 이름이다. 만약 모듈에 있는 모든 어트리뷰트를 불러오려면 다음과 같은 방식으로 사용하면 된다.

 

>>> from arithmetic import *

>>> plus(1, 2)

3

>>> minus(4, 2)

2

>>> mul(5, 5)

25

>>> div(10, 2)

5.0

 

위 예제에서 'from 모듈명 import *'와 같은 식으로 쓰이면 arithmetic 모듈에 있는 모든 어트리뷰트를 불러온다. 이 경우에도 따로 모듈명을 적지 않고도 직접 참조가 가능하다.

 

 

2) IDLE를 활용한 모듈 만들기

파이썬에는 다양한 기능을 수행하는 모듈이 기본적으로 제공되며 파이썬을 설치할 때 함께 설치된다.

파이썬으로 프로그래밍하다 보면 많은 부분을 파이썬의 모듈을 통해 구현해야 하며 파이썬 모듈이란 자주 사용되는 기능에 대해 이미 코드로 구현해둔 것이기 때문에 파이썬 모듈을 이용하면 직접 특정 기능을 구현하는 것보다 쉽고 빠르게 프로그램을 개발할 수 있다.

 

다음 그림과 같이 파이썬 IDLE를 실행한다.

(시작-프로그램-python3.6-IDLE(Python 3.6.x-bit)

 

 

 

 

 

 

File 메뉴를 선택한 후 New File을 선택한다.

 

 

새 창에 다음과 같이 코드를 작성한다. 함수를 구현하고 추가로 author라는 변수가 pystock이라는 문자열을 바인딩하게 했다. 한 가지 주의할 점은 다음 코드는 말 그대로 파이썬 코드이므로 >>>와 같은 파이썬 프롬프트가 없다는 점이다.

 

 

 

def cal_upper(price):

increment = price * 0.3

upper_price = price + increment

return upper_price

 

def cal_lower(price):

decrement = price * 0.3

lower_price = price - decrement

return lower_price

 

author = "pystock"

 

코드를 작성한 후 그림과 같이 [File]-[Save] 메뉴를 클릭해 파일로 저장한다.

 

 

파이썬 코드를 파일로 저장할 때 다음 그림과 같이 저장될 파일의 경로를 C:/Anaconda3 디렉터리에 저장해야 한다.

 

 

 

 

지금까지 작업한 내용을 요약해보면 함수를 구현하고 이를 stock.py라는 이름으로 하드디스크에 저장했다.

이제 앞에서 작성한 stock이라는 모듈을 사용해 보자. 모듈을 사용하려면 모듈을 임포트해야 한다.

 

 

 

 

 

그림과 같이 파이썬 IDLE에서 stock 모듈을 임포트한다. 여기서 오류가 발생하지 않으면 stock 모듈을 잘 만들었고 해당 모듈이 정상적으로 임포트된 것이다.

 

앞에서 구현한 stock 모듈에는 author라는 변수와 cal_uppercal_lower라는 함수가 있었다. 파이썬에서는 모듈을 임포트하면 모듈 내에 구현된 함수나 변수를 사용할 수 있다.

먼저 다음과 같이 stock 모듈 내에 있던 변수 author를 화면에 출력해 본다. 이때 author라는 변수명을 바로 적으면 안 되고 stock.author라고 적어야 한다. 모듈 내의 함수나 변수명에 접근할 때는 항상 '모듈명.함수명(변수명)'과 같은 형태로 적어야 한다.

 

>>> print(stock.author)

pystock

>>>

 

다음은 stock 모듈 내에 구현된 함수를 호출해 본다. 함수 역시 먼저 모듈명을 적은 후 '.'를 붙이고 함수명을 적어야 한다. 이렇게 하는 이유는 해당 함수가 stock이라는 모듈 내에 정의돼 있다는 것을 명시적으로 알려주기 위해서이다. stock.py 파일에 구현된 cal_uppercal_lower 함수를 사용할 수 있음을 확인할 수 있다.

 

>>> stock.cal_upper(10000)

13000.0

>>> stock.cal_lower(10000)

7000.0

>>>

 

모듈을 개발하고 이를 배포하고자 한다면 모듈에 구현된 함수가 정상적으로 동작하는지 충분히 테스트한 후 모듈을 배포해야 한다. 이를 위해서는 모듈 파일 내에서 함수를 직접 호출하는 테스트 코드를 구현하는 것이 좋다.

 

다음과 같이 stock.py 파일에 cal_uppercal_lower 함수를 호출하는 코드를 추가해 준다. 그리고 print(__name__)도 추가해준다.

 

def cal_upper(price):

increment = price * 0.3

upper_price = price + increment

return upper_price

 

def cal_lower(price):

decrement = price * 0.3

lower_price = price - decrement

return lower_price

 

author = "pystock"

 

print(cal_upper(10000))

print(cal_lower(10000))

print(__name__)

 

 

수정 된 stock.py 파일을 실행하려면 그림과 같이 [Run]-[Run Module] 메뉴를 차례로 선택한다.

 

 

 

 

파이썬 IDLE에 다음과 같이 stock.py 파일의 실행 결과가 출력된다.

print(__name__)의 결과로 __main__이라는 문자열이 화면에 출력됨을 확인할 수 있다.

>>>

======================= RESTART: C:\Anaconda3\stock.py =======================

13000.0

7000.0

__main__

>>>

 

 

업데이트된 stock 모듈을 다시 임포트 해보자. stock 모듈을 임포트하면 앞서 추가했던 print 구문의 결과값이 출력됨을 확인할 수 있다. 모듈을 테스트하는 입장에서는 모듈 내에 테스트 코드를 넣는 방식은 유용하지만, 모듈을 사용하는 입장에서는 임포트할 때 모듈을 테스트하는 코드가 같이 실행되는 것은 불필요한 기능이다.

 

>>> import stock

13000.0

7000.0

stock

>>>

 

여기서 한가지 눈여겨볼 점은 모듈을 직접 실행했을 때는 print(__name__)의 결과로 __main__이라는 문자열이 출력되지만, 해당 모듈을 임포트했을 때는 모듈의 이름인 stock이라는 문자열이 출력된다는 점이다.

 

, 파이썬에서 __name__이라는 변수는 파이썬 자체에서 사용하는 변수로 특정 파이썬 파일이 직접 실행된 것인지 또는 다른 파이썬 파일에서 임포트 된 것인지를 확인하는 용도로 사용된다. 특정 파이썬 파일이 독립적으로 실행됐다면 __name__이라는 변수는 __main__이라는 문자열을 바인딩하며 다른 파일에 임포트 된 경우에는 자신의 파일명을 바인딩한다.

 

파이썬의 __name__이라는 변수를 사용하면 앞서 모듈의 테스트 코드가 모듈을 임포트했을 때 자동으로 호출되는 문제를 해결할 수 있다. stock.py 파일에 추가했던 테스트 코드를 다음과 같이 수정한다.

 

if __name__ == "__main__":

print(cal_upper(10000))

print(cal_lower(10000))

print(__name__)

 

 

추가된 코드의 의미를 살펴보면 __name__이라는 파이썬 변수가 바인딩하고 있는 값이 __main__이라는 문자열이라면 들여쓰기 된 세 개의 print문을 실행한다. , stock.py 파일이 직접 실행이 된 경우라면 세 개의 print문이 실행된다. 만약 다른 파일에 stock.py 파일(모듈)이 임포트 된다면 __name__은 모듈의 이름인 stock을 바인딩하므로 if 문의 조건식을 만족하지 않고 따라서 세 개의 print문도 실행되지 않는다.

 

stock.py 파일을 수정했다면 stock 모듈을 다시 임포트해본다. stock.py 파일에 여전히 모듈을 테스트하는 코드가 존재하지만 해당 코드가 실행되지 않았음을 확인할 수 있다.

 

Python 3.5.2 |Anaconda 4.1.1 (32-bit)| (default, Jul 5 2016, 11:45:57) [MSC v.1900 32 bit (Intel)] on win32

Type "copyright", "credits" or "license()" for more information.

>>> import stock

>>>

 

그림과 같이 stock.py 파일을 직접 실행시키면 다음과 같이 여전히 테스트가 코드가 출력됨을 확인할 수 있다.

>>>

======================= RESTART: C:\Anaconda3\stock.py =======================

13000.0

7000.0

__main__

>>>

 

 

 

 

 

3) 파이썬에서 시간 다루기

알고리즘 트레이딩을 하려면 파이썬에서 시간을 잘 다룰 수 있어야 한다.

 

, 파이썬에서 시간과 날짜를 다루는 방법이다.

 

앞에서 파이썬의 모듈을 학습했는데, 파이썬에서 시간을 다루는 가장 쉬운 방법은 모듈을 사용하는 것이다. 파이썬에는 시간과 날짜를 다루기 위한 timedatetime이라는 기본 모듈이 있다.

 

먼저 time 모듈을 사용해 보자.

다음과 같이 time 모듈을 사용하려면 먼저 time 모듈을 임포트해야 한다.

여기서 모듈의 이름이 time인 이유는 파일명이 time.py이기 때문이다. time 모듈에서 현재 시각을 구하는 함수는 time()이다. time()은 현재 시각을 반환하는 함수인데 197011000초를 기준으로 초 단위로 지난 시간을 알려준다.

 

>>> import time

>>> time.time()

1444532446.467043

>>> time.ctime()

'Sat Nov 11 12:00:50 2017'

>>> type(_)

<class 'str'>

>>>

 

위 코드를 보면 time.time()의 결과가 우리가 알기 어려운 실수 형태로 반환됐음을 확인할 수 있다. 사람들이 좀 더 쉽게 읽을 수 있는 시간을 구하려면 ctime() 함수를 사용하면 된다. ctime() 함수의 결과를 확인하면 '20171111120050'임을 확인할 수 있다.

 

ctime() 함수의 반환값인 'Sat Nov 11 12:00:50 2017'은 문자열처럼 보이긴 하지만 정확한 타입을 확인하기 위해 type() 함수를 사용했다. 여기서 type() 함수의 인자로 _를 사용했는데 파이썬 IDLE에서 _는 가장 최근의 반환값을 바인딩하고 있는 변수이다.

위 코드에서 type(_) 코드가 나오기 전에 가장 최근의 값은 time.ctime() 함수의 반환값이므로 type(_) 의미는 time.ctime() 함수의 반환값에 대한 타입을 확인하는 것이 된다. 또한, <class 'str'>, 즉 문자열 타입임을 알 수 있다.

 

time.ctime()의 반환값에서 연도(year)만 구하려면 앞서 time.ctime()의 반환값이 문자열이었으므로 문자열에서 제공하는 메서드를 사용하면 된다.

 

다음 코드는 time.ctime() 함수의 반환값을 cur_time이라는 변수가 바인딩하게 한 후 문자열 객체가 제공하는 split이라는 메서드를 사용해 공백을 기준으로 문자열을 분리했다.

분리된 문자열 중 맨 마지막에 존재하는 원소를 화면에 출력하면 연도가 화면에 출력 된다.

 

>>> cur_time = time.ctime()

>>> print(cur_time.split(' ')[-1])

2017

>>>

 

이번에는 time 모듈의 sleep() 함수를 이용해 프로그램을 잠깐 잠재워 보자. time 모듈의 sleep() 함수는 인자로 전달되는 값에 해당하는 초(sec) 동안 코드의 실행을 멈추는 역할을 한다.

예를 들어, 다음 코드는 0부터 9까지의 숫자를 출력하는데, 1초 간격으로 숫자를 출력하는 코드이다. 코드를 실행하면 파이썬 IDLE에서 숫자가 1초 간격으로 출력되는 것을 확인할 수 있다.

 

>>> for i in range(10):

print(i)

time.sleep(1)

 

앞에서 설명한 것처럼 파이썬에서 모듈은 파이썬 파일을 의미합니다. 그러나 모듈의 실행 속도가 중요한 일부 모듈은 파이썬으로 작성되지 않고 C 언어로 작성된다. 이 경우에는 해당 모듈의 코드를 직접 볼 수는 없다.

다음 코드는 time 모듈과 random 모듈을 임포트한 후 해당 모듈의 위치를 확인하는 코드이다. time 모듈은 내장 모듈이기 때문에 해당 모듈의 위치가 따로 출력되지는 않지만 random 모듈은 해당 모듈이 위치하는 경로가 출력되는 것을 볼 수 있다.

 

>>> import time

>>> time

<module 'time' (built-in)>

>>> import random

>>> random

<module 'random' from 'C:\\Anaconda3\\lib\\random.py'>

>>>

 

파이썬 모듈에는 여러 기능을 수행하는 함수와 변수들이 있을 수 있는데 모듈 안에 어떤 함수나 변수가 있는지 어떻게 확인할 수 있다.

가장 간단한 방법은 다음과 같이 dir() 함수를 사용하는 것이다. 임포트된 모듈에 대해 모듈명을 사용해 dir() 내장 함수를 호출하면 해당 모듈의 구성 요소를 확인할 수 있다.

 

 

>>> import time

>>> dir(time)

['_STRUCT_TM_ITEMS', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'altzone', 'asctime', 'clock', 'ctime', 'daylight', 'get_clock_info', 'gmtime', 'localtime', 'mktime', 'monotonic', 'perf_counter', 'process_time', 'sleep', 'strftime', 'strptime', 'struct_time', 'time', 'timezone', 'tzname']

>>>

 

 

 

4) OS 모듈

파이썬에는 기본적으로 제공되는 다양한 모듈이 있는데, 이 모듈들은 모두 유용하게 사용되지만 가장 자주 사용되는 모듈 가운데 os라는 모듈이 있다. os 모듈은 Operating System의 약자로 운영체제에서 제공되는 여러 기능을 파이썬에서 수행할 수 있게 해준다.

 

예를 들어, 파이썬을 이용해 파일을 복사하거나 디렉터리를 생성하고 특정 디렉터리 내의 파일 목록을 구하고자 할 때 os 모듈을 사용하면 된다.

 

먼저 현재 경로를 구하려면 os 모듈의 getcwd() 함수를 사용하면 된다.

다음 코드를 보면 현재 경로로 C:\Anaconda3\Lib\idlelib이 반환되는 것을 확인할 수 있다. 이는 현재 파이썬 IDLE가 해당 경로에서 실행됐기 때문이다.

 

>>> import os

>>> os.getcwd()

'C:\\Anaconda3\\Lib\\idlelib'

>>>

 

 

 

getcwd() 함수는 현재 경로를 얻을 수 있다.

 

이번에는 특정 경로에 존재하는 파일과 디렉터리 목록을 구하는 함수인 listdir() 함수를 사용해보자.

 

다음 코드를 보면 현재 경로인 C:\Anaconda3\Lib\idlelib에 존재하는 파일과 디렉터리 목록이 리스트로 구성된 후 반환되는 것을 확인할 수 있다.

 

>>> os.listdir()

['aboutDialog.py', 'AutoComplete.py', 'AutoCompleteWindow.py', 'AutoExpand.py', 'Bindings.py', 'CallTips.py', 'CallTipWindow.py', 'ChangeLog', 'ClassBrowser.py', 'CodeContext.py', 'ColorDelegator.py', 'config-extensions.def', 'config-highlight.def', 'config-keys.def', 'config-main.def', 'configDialog.py', 'configHandler.py', 'configHelpSourceEdit.py', 'configSectionNameDialog.py', 'CREDITS.txt', 'Debugger.py', 'Delegator.py', 'dynOptionMenuWidget.py', 'EditorWindow.py', 'extend.txt', 'FileList.py', 'FormatParagraph.py', 'GrepDialog.py', 'help.txt', 'HISTORY.txt', 'HyperParser.py', 'Icons', 'idle.bat', 'idle.py', 'idle.pyw', 'IdleHistory.py', 'idlever.py', 'idle_test', 'IOBinding.py', 'keybindingDialog.py', 'macosxSupport.py', 'MultiCall.py', 'MultiStatusBar.py', 'NEWS.txt', 'ObjectBrowser.py', 'OutputWindow.py', 'ParenMatch.py', 'PathBrowser.py', 'Percolator.py', 'PyParse.py', 'PyShell.py', 'README.txt', 'RemoteDebugger.py', 'RemoteObjectBrowser.py', 'ReplaceDialog.py', 'rpc.py', 'RstripExtension.py', 'run.py', 'ScriptBinding.py', 'ScrolledList.py', 'SearchDialog.py', 'SearchDialogBase.py', 'SearchEngine.py', 'StackViewer.py', 'tabbedpages.py', 'textView.py', 'TODO.txt', 'ToolTip.py', 'TreeWidget.py', 'UndoDelegator.py', 'WidgetRedirector.py', 'WindowList.py', 'ZoomHeight.py', '__init__.py', '__main__.py', '__pycache__']

>>>

 

listdir() 함수의 인자로 경로를 전달하는 경우 해당 경로에 존재하는 파일과 디렉터리 목록을 구할 수 있다.

 

다음 코드는 listdir() 함수의 인자로 'c:/Anaconda3'을 전달한 경우이다. 이처럼 listdir() 함수의 인자로 특정 경로를 지정하는 경우 해당 경로에 있는 파일과 디렉터리 목록이 반환된다.

 

>>> os.listdir('c:/Anaconda3')

['conda-meta', 'DLLs', 'Doc', 'envs', 'Examples', 'include', 'info', 'Lib', 'Library', 'libs', 'licenses', 'LICENSE_PYTHON.txt', 'Menu', 'node-webkit', 'pkgs', 'python.exe', 'python34.dll', 'pythonw.exe', 'qt.conf', 'Scripts', 'share', 'stock.py', 'tcl', 'Tools', 'Uninstall-Anaconda.exe', 'xlwings32.dll', 'xlwings64.dll', '__pycache__']

>>>

 

윈도우의 파일 탐색기를 이용해 'c:/Anaconda3' 경로로 이동한 후 파일과 디렉터리 목록을 확인하고 위 코드에서 listdir() 함수 반환값과 한 번 비교해 보기 바란다.

 

 

 

 

해당 경로에 총 몇 개의 파일 또는 디렉터리가 존재하는지 확인해 보자.

listdir() 함수의 반환값은 파이썬 리스트인데, 리스트, 튜플, 문자열 등에서 원소의 개수를 세기 위해서는 len() 함수를 사용하면 된다.

다음은 listdir() 함수의 반환값에 대해 len() 함수를 사용한 예이다.

해당 경로에는 80개의 파일 또는 디렉터리가 존재하는 것을 확인할 수 있다.

참고로 type() 함수를 이용해 listdir() 함수의 반환값 타입을 확인해보면 리스트임을 확인할 수 있다.

 

>>> files = os.listdir('c:/Anaconda3')

>>> len(files)

80

>>> type(files)

<class ‘list’>

>>>

 

 

이번에는 'c:/Anaconda3'이라는 경로에 있는 파일 중 확장자가 'exe'로 끝나는 파일만 출력하는 코드를 작성해 보자.

이를 위해서는 listdir() 함수와 if , 문자열의 endswith() 메서드를 조합하면 된다.

다음을 보면 'c:/Anaconda3' 경로에 있는 파일 목록 중 문자열이 'exe'로 끝나는 경우를 출력하는 것을 확인할 수 있다.

 

>>> for x in os.listdir('c:/Anaconda3'):

if x.endswith('exe'):

print(x)

 

python.exe

pythonw.exe

Uninstall-Anaconda.exe

>>>

 

 

5) 모듈을 임포트하는 세 가지 방법

모듈을 임포트할 때 'import 모듈명'이라는 규칙을 사용했다. 그런데 다른 사람이 작성한 파이썬 코드를 보다 보면 다양한 형태로 모듈을 임포트하는 코드를 볼 수 있다.

1. 모듈 임포트하기

다음 소스 코드와 같이 import 문을 이용하여서 모듈을 임포트할 수 있다.

모듈은 .py 확장자가 없는 파이썬 파일의 이름으로 import 한 모듈 이름에 . 을 붙인 후, 모듈에 포함된 변수, 함수, 클래스 등을 사용할 수 있다.

 

import sys

print( "input args:", sys.argv )

 

2. 다른 이름으로 모듈 임포트하기

sys 모듈을 main 이란 이름으로 사용하고 싶은 경우에는 다음과 같이 as 구문

이용한다.

 

import sys as main

print( "input args:", main.argv )

 

3. 필요한 모듈만 임포트하기

모듈 전체가 아닌 모듈에서 필요한 변수, 함수, 클래스만 임포트하려면 다음과 같이 from 구문을 이용한다.

 

from sys import argv

print( "input args:", argv )

 

또한 필요한 변수, 함수, 클래스를 다른 이름으로 사용하고 싶은 경우에는 다음과 같이 as 구문을 이용한다.

 

from sys import argv as test

print( "input args:", test )

 

먼저 파이썬 IDLE를 새롭게 실행한 후 dir() 함수를 파이썬 IDLE에서 호출해 본다.

 

>>> dir()

['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__']

>>>

 

이번에는 os 모듈을 임포트한 후 다시 dir() 함수를 호출해 이전 dir() 함수의 결과값과 비교해 본다. 차이점은 os 모듈을 임포트한 후에는 os라는 이름이 dir() 함수의 결과값 리스트에 추가된 것을 확인할 수 있다. 이처럼 os라는 이름이 추가됐기 때문에 os라는 이름을 사용하는 os.listdir()과 같은 표현이 가능했던 것이다.

 

>>> import os

>>> dir()

['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'os']

>>>

 

 

 

 

다음은 모듈을 임포트하는 두 번째 방법이다.

 

열려 있던 파이썬 IDLE를 닫고 새로 파이썬 IDLE를 실행한 후 다음과 같이 실행해본다.

'from os import listdir' 구문의 의미는 "os 모듈로부터(from) listdir을 임포트하라"이다. 두 번째 방식으로 모듈을 임포트한 경우 dir()의 결과값 리스트에는 os가 아니라 os 모듈에 구현된 listdir 함수만 존재하는 것을 확인할 수 있다.

 

>>> from os import listdir

>>> dir()

['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'listdir']

>>>

 

 

 

따라서 다음과 같이 os라는 모듈명을 사용하거나 os.listdir()과 같이 os 모듈 내의 listdir() 함수를 호출할 경우 오류가 발생한다. listdir()과 같이 해당 함수를 직접 이용하는 방법만 가능하다.

 

>>> os

Traceback (most recent call last):

File "<pyshell#3>", line 1, in <module>

os

NameError: name 'os' is not defined

>>> os.listdir()

Traceback (most recent call last):

File "<pyshell#4>", line 1, in <module>

os.listdir()

NameError: name 'os' is not defined

>>> listdir()

 

모듈 내의 함수를 호출할 때 모듈을 임포트하는 첫 번째 방식에서는 '모듈명.함수명' 형태로 사용했는데, 두 번째 방식은 함수 이름만으로도 바로 함수 호출이 가능하므로 프로그래밍할 코드의 수가 적어진다는 장점이 있다.

다만 두 번째 방식은 기존에 선언된 변수나 함수와 이름이 충돌할 가능성이 있다.

 

예를 들어, "김철수"라는 이름이 "종로"에도 있고 "종각"에도 있을 때 "종로.김철수", "종각.김철수"와 같은 식으로 표현하면 서로 구분할 수 있다. 그런데 지역을 빼고 "김철수"라고 하면 부를 때는 좋지만 누가 누군지 모르는 경우가 발생한다.

listdir이라는 이름을 사용자가 만든 함수나 변수에서 이미 사용 중이라면 'from os import listdir'을 하는 순간 해당 이름의 변수나 함수가 없어지고 os 모듈의 listdir로 대체되는데, 이러한 것들이 나중에는 잠재적인 프로그램의 버그가 될 수 있다.

 

모듈을 임포트하는 세 번째 방식은 모듈 내의 모든 것을 임포트하는 것이다. 이전과 마찬가지로 IDLE를 새로 실행한 후 다음 코드를 실행한다. 'from os import *'"os 모듈 내의 모든 것을 임포트하라"라는 의미이다.

따라서 dir() 함수의 결과값을 보면 os 모듈이 지원하는 함수나 변수가 모두 리스트에 포함된 것을 확인할 수 있다.

 

>>> from os import *

>>> dir()

['F_OK', 'O_APPEND', 'O_BINARY', 'O_CREAT', 'O_EXCL', 'O_NOINHERIT', 'O_RANDOM', 'O_RDONLY', 'O_RDWR', 'O_SEQUENTIAL', 'O_SHORT_LIVED', 'O_TEMPORARY', 'O_TEXT', 'O_TRUNC', 'O_WRONLY', 'P_DETACH', 'P_NOWAIT', 'P_NOWAITO', 'P_OVERLAY', 'P_WAIT', 'R_OK', 'SEEK_CUR', 'SEEK_END', 'SEEK_SET', 'TMP_MAX', 'W_OK', 'X_OK', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', '_exit', 'abort', 'access', 'altsep', 'chdir', 'chmod', 'close', 'closerange', 'cpu_count', 'curdir', 'defpath', 'device_encoding', 'devnull', 'dup', 'dup2', 'environ', 'error', 'execl', 'execle', 'execlp', 'execlpe', 'execv', 'execve', 'execvp', 'execvpe', 'extsep', 'fdopen', 'fsdecode', 'fsencode', 'fstat', 'fsync', 'get_exec_path', 'get_handle_inheritable', 'get_inheritable', 'get_terminal_size', 'getcwd', 'getcwdb', 'getenv', 'getlogin', 'getpid', 'getppid', 'isatty', 'kill', 'linesep', 'link', 'listdir', 'lseek', 'lstat', 'makedirs', 'mkdir', 'name', 'open', 'pardir', 'path', 'pathsep', 'pipe', 'popen', 'putenv', 'read', 'readlink', 'remove', 'removedirs', 'rename', 'renames', 'replace', 'rmdir', 'sep', 'set_handle_inheritable', 'set_inheritable', 'spawnl', 'spawnle', 'spawnv', 'spawnve', 'startfile', 'stat', 'stat_float_times', 'stat_result', 'statvfs_result', 'strerror', 'supports_bytes_environ', 'symlink', 'system', 'terminal_size', 'times', 'times_result', 'umask', 'uname_result', 'unlink', 'urandom', 'utime', 'waitpid', 'walk', 'write']

>>>

 

세 번째 방식으로 os 모듈을 임포트했을 때 listdir()을 사용하려면 두 번째 방식과 동일하게 listdir()을 바로 사용하면 된다. 참고로 세 번째 방식도 두 번째 방식과 마찬가지로 기존에 listdir() 이라는 이름의 함수가 이미 있는 경우 이름 충돌과 관련된 문제가 발생할 수 있다.

 

그렇다면 모듈을 임포트하는 가장 좋은 방법 또는 일반적으로 추천되는 스타일은 첫 번째 방식입니다. 모듈을 임포트할 때는 'import 모듈명'을 사용하고, 모듈 내의 함수 또는 변수를 사용할 때는 '모듈명.함수명(변수)'의 형태를 사용하는 것이다.

 

그러나 이따금 모듈명이 너무 긴 경우가 있다. 또는 모듈명이 너무 짧아서 모듈의 이름만으로는 정확히 구분하기가 어려워 모듈명을 다르게 사용하고 싶을 때도 있을 것이다. 이 경우 다음과 같이 모듈을 임포트할 때 이름을 변경할 수도 있다.

 

'import os as winos'의 의미는 "os 모듈을 winos로 임포트하라"이다.

dir() 함수의 결과값을 확인해보면 os 대신 winos 항목이 결과값 리스트에 있는 것을 확인할 수 있다.

따라서 os 모듈 내에 있던 함수를 사용할 때도 os.getcwd()가 아니라 winos.getcwd()와 같이 사용해야 한다.

 

>>> import os as winos

>>> dir()

['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'winos']

>>> winos.getcwd()

'C:\\Anaconda3\\Lib\\idlelib'

>>>

 

 

 

 

 

 

[함수 응용 예제] 앞서 구현한 요일을 구하는 프로그램을 함수화 시키는 프로그램

 

[출력 결과]

 

 

 

# 년월일을 입력받는 함수이다.

# 반환값: 년월일을 튜플 형태로 반환

def input_date(): # , , 일을 입력받아 튜플 형태로 반환해준다.

year = int(input("년도를 입력하시오: "))

month = int(input("월을 입력하시오: "))

day = int(input("일을 입력하시오: "))

return year, month, day

 

# 윤년인지를 확인하는 함수이다.

# 입력인자: year: 년도

# 반환값: True: 윤년이다, False: 윤년이 아니다.

def is_leap(year):

if year % 400 == 0:

return True

elif year % 100 == 0:

return False

elif year % 4 == 0:

return True

else:

return False

 

# 요일을 구하는 함수이다.

# 입력인자: year: 년도, month: , day:

# 반환값: 요일

def get_day_name(year, month, day): # , , 일을 입력받아 요일을 구해주며, 이 함수

# 내에서는 특정 년도가 윤년인지 아닌지를 확인하기

# 위해 is_leap 함수를 호출한다.

 

total_days = 0

 

year_month_days = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]

day_names = ["일요일","월요일","화요일","수요일","목요일","금요일","토요일"]

 

for item in range(1, year):

if is_leap(item):

total_days = total_days + 366

else:

total_days = total_days + 365

 

for item in range(1, month):

total_days = total_days + year_month_days[item]

 

if month >= 3:

if is_leap(year):

total_days = total_days + 1

else:

total_days = total_days + 0

 

total_days += day

remainder = total_days % 7

return day_names[remainder]

 

if __name__ == "__main__":

year, month, day = input_date()

day_name = get_day_name(year, month, day)

print(day_name)

 

 

 

[함수 응용 예제 1] 성적 처리 시스템 구현을 통한 함수 활용 프로그램

 

[출력 결과]

 

 

 

# 학생들의 총점을 구하는 함수

def calculate_total(students):

for student in students:

student["total"] = student["kor"] + student["eng"] + student["math"]

 

# 학생들의 평균을 구하는 함수

def calculate_average(students):

for student in students:

student["avg"] = student["total"] / len(students)

 

# 학생들의 등수를 구하는 함수

def calculate_order(students):

temp_students = sorted(students, key = lambda x: x["total"], reverse=True)

order = 1

for student in temp_students:

student["order"] = order

order = order + 1

 

return temp_students

 

# 반 평균을 구하는 함수

def calculate_class_avg(students):

class_total = 0

 

for student in students:

class_total = class_total + student["total"]

 

return class_total / len(students)

 

# 반의 국어 평균을 구하는 함수

def calculate_kor_avg(students):

kor_total = 0

 

for student in students:

kor_total = kor_total + student["kor"]

 

return kor_total / len(students)

 

# 반의 영어 평균을 구하는 함수

def calculate_eng_avg(students):

eng_total = 0

 

for student in students:

eng_total = eng_total + student["eng"]

 

return eng_total / len(students)

 

# 반의 수학 평균을 구하는 함수

def calculate_math_avg(students):

math_total = 0

 

for student in students:

math_total = math_total + student["math"]

 

return math_total / len(students)

 

# 학생 데이터를 출력하는 함수

def print_student(students):

for student in students:

print("번호: %s, 이름: %s, 국어: %d, 영어: %d, 수학: %d, 총점: %d, 평균: %.2f,

등수: %d" % (student["num"], student["name"], student["kor"],

student["eng"], student["math"], student["total"], student["avg"],

student["order"]))

 

# 반의 평균 및 각 과목의 평균을 구하는 함수

def print_class(class_avg, kor_avg, eng_avg, math_avg):

print("반 평균: %.2f" % class_avg)

print("국어 평균: %.2f" % kor_avg)

print("영어 평균: %.2f" % eng_avg)

print("수학 평균: %.2f" % math_avg)

 

 

def main():

students = [{"num": "1", "name":"김민규", "kor": 90, "eng": 80, "math": 85,

"total": 0.0, "order": 0}, {"num": "2", "name":"김용학", "kor": 90,

"eng": 85, "math": 90, "total": 0.0, "order": 0},{"num": "3", "name":"

박영철", "kor": 80, "eng": 80, "math": 80, "total": 0.0, "order": 0}]

 

class_avg = 0.0

kor_avg = 0.0

eng_avg = 0.0

math_avg = 0.0

 

calculate_total(students) # 학생의 총점 계산

calculate_average(students) # 학생의 평균 계산

students = calculate_order(students) # 학생의 등수 계산

 

class_avg = calculate_class_avg(students) # 반 평균 계산

kor_avg = calculate_kor_avg(students) # 반 국어 평균 계산

eng_avg = calculate_eng_avg(students) # 반 영어 평균 계산

math_avg = calculate_math_avg(students) # 반 수학 평균 계산

 

print_student(students) # 학생들 데이터 출력

print()

print_class(class_avg, kor_avg, eng_avg, math_avg) # 반 평균, 각 과목 평균 출력

 

if __name__ == "__main__":

main()

 

 

 

[응용 예제] 위 성적 처리 코드를 모듈화하여 실행하는 다양한 방법

 

[첫 번째 방법]

다음과 같이 모듈로 작성한 후 lib에 넣은 후

def calculate_total(students):

for student in students:

student["total"] = student["kor"] + student["eng"] + student["math"]

 

def calculate_average(students):

for student in students:

student["avg"] = student["total"] / len(students)

 

def calculate_order(students):

temp_students = sorted(students, key = lambda x: x["total"], reverse = True)

order = 1

for student in temp_students:

student["order"] = order

order = order + 1

 

return temp_students

 

def calculate_class_avg(students):

class_total = 0

 

for student in students:

class_total = class_total + student["total"]

 

return class_total / len(students)

 

def calculate_kor_avg(students):

kor_total = 0

 

for student in students:

kor_total = kor_total + student["kor"]

 

return kor_total / len(students)

 

def calculate_eng_avg(students):

eng_total = 0

 

for student in students:

eng_total = eng_total + student["eng"]

 

return eng_total / len(students)

 

def calculate_math_avg(students):

math_total = 0

 

for student in students:

math_total = math_total + student["math"]

 

return math_total / len(students)

 

def print_student(students):

for student in students:

print("번호: %s, 이름: %s, 국어: %d, 영어: %d, 수학: %d, 총점: %d,

평균: %.2f, 등수: %d" % (student["num"], student["name"],

student["kor"], student["eng"], student["math"],

student["total"], student["avg"], student["order"]))

 

def print_class(class_avg, kor_avg, eng_avg, math_avg):

print("반 평균 : %.2f" % class_avg)

print("국어 평균 : %.2f" % kor_avg)

print("영어 평균 : %.2f" % eng_avg)

print("수학 평균 : %.2f" % math_avg)

 

다음 코드를 실행 하면 성적이 다음과 같이 출력된다.

import test002

students = [{"num": "1", "name":"김민규", "kor": 90, "eng": 80, "math":85, "total": 0.0, "order":0},{"num": "2", "name":"김용학", "kor": 90, "eng": 85, "math":90, "total": 0.0, "order":0},{"num": "3", "name":"박영철", "kor": 80, "eng": 80, "math":80, "total": 0.0, "order":0}]

 

class_avg = 0.0

kor_avg = 0.0

eng_avg = 0.0

math_avg = 0.0

 

test002.calculate_total(students) #학생 총점

test002.calculate_average(students) #학생 평균

students = test002.calculate_order(students) #학생 등수

 

class_avg = test002.calculate_class_avg(students)

kor_avg = test002.calculate_kor_avg(students)

eng_avg = test002.calculate_eng_avg(students)

math_avg = test002.calculate_math_avg(students)

 

test002.print_student(students)

print()

test002.print_class(class_avg, kor_avg, eng_avg, math_avg)

 

 

 

 

-------------------------------------------------------------------

[두 번째 방법]

다음과 같이 각 과목, 총점, 평균, 등수 등을 모듈로 작성한 후

[stu_avg]

#coding:euc-kr

def calculate_average(students) :

for student in students :

student["avg"] = student["total"] / len(students)

 

[stu_class_avg]

#coding:euc-kr

def calculate_class_avg(students) :

class_total = 0

 

for student in students :

class_total = class_total + student["total"]

 

return class_total / len(students)

 

[stu_eng_avg]

#coding:euc-kr

def calculate_eng_avg(students) :

eng_total = 0

 

for student in students :

eng_total = eng_total + student["eng"]

 

return eng_total / len(students)

 

[stu_kor_eng]

#coding:euc-kr

def calculate_kor_avg(students) :

kor_total = 0

 

for student in students :

kor_total = kor_total + student["kor"]

 

return kor_total / len(students)

 

[stu_math_avg]

#coding:euc-kr

def calculate_math_avg(students) :

math_total = 0

 

for student in students :

math_total = math_total + student["math"]

 

return math_total / len(students)

 

[stu_rank]

#coding:euc-kr

def calculate_order(students) :

temp_students = sorted(students, key = lambda x : x["total"], reverse

= True)

order = 1

 

for student in temp_students :

student["order"] = order

order += 1

 

return temp_students

 

[stu_total]

#coding:euc-kr

def calculate_total(students) :

for student in students :

student["total"] = student["kor"] + student["eng"] +

student["math"]

 

 

import를 활용하여 위에서 작성한 모듈을 불러와서 실행하면 다음과 같이 결과를 확인할 수 있다.

 

#coding:euc-kr

def print_student(students) :

for student in students :

print("번호 : %s, 이름 : %s, 국어 : %d, 영어 : %d, 수학 : %d, 총점 : %d, 평균 : %.2f, 등수 : %d" %(student["num"], student["name"], student["kor"], student["eng"], student["math"], student["total"], student["avg"], student["order"]))

 

def print_class(class_avg, kor_avg, eng_avg, math_avg) :

print("반 평균 : %.2f" %class_avg)

print("국어 평균 : %.2f" %kor_avg)

print("영어 평균 : %.2f" %eng_avg)

print("수학 평균 : %.2f" %math_avg)

 

def main() :

students = [{"num":"1", "name":"김민규", "kor":90, "eng":80, "math":85,

"total":0.0, "order":0}, {"num":"2", "name":"김용학",

"kor":90, "eng":85, "math":90, "total":0.0, "order":0},

{"num":"3", "name":"박영철", "kor":80, "eng":80, "math":80,

"total":0.0, "order":0}]

 

class_avg = 0.0

kor_avg = 0.0

eng_avg = 0.0

math_avg = 0.0

 

import stu_total, stu_avg, stu_rank, stu_class_avg, stu_kor_avg,

stu_eng_avg, stu_math_avg

# 총점

stu_total.calculate_total(students)

# 평균

stu_avg.calculate_average(students)

# 석차

students = stu_rank.calculate_order(students)

# 반평균

class_avg = stu_class_avg.calculate_class_avg(students)

# 국어평균

kor_avg = stu_kor_avg.calculate_kor_avg(students)

# 영어평균

eng_avg = stu_eng_avg.calculate_eng_avg(students)

# 수학평

math_avg = stu_math_avg.calculate_math_avg(students)

 

print_student(students)

print()

print_class(class_avg, kor_avg, eng_avg, math_avg)

 

if __name__ == "__main__" :

main()

 

 

 

 

[세 번째 방법]

다음과 같이 예제 함수를 각각의 모듈로 생성한 후

[cal_main]

import calculate

import printed

 

def main():

students = [{"num": "1", "name": "김민규", "kor": 90, "eng": 80, "math":

85, "total": 0.0, "order": 0},

{"num": "2", "name": "김용학", "kor": 90, "eng": 85, "math":

90, "total": 0.0, "order": 0},

{"num": "3", "name": "박영철", "kor": 80, "eng": 80, "math":

80, "total": 0.0, "order": 0}]

 

class_avg = 0.0

kor_avg = 0.0

eng_avg = 0.0

math_avg = 0.0

 

calculate.calculate_total(students)

calculate.calculate_average(students)

students = calculate.calculate_order(students)

 

class_avg = calculate.calculate_class_avg(students)

kor_avg = calculate.calculate_kor_avg(students)

eng_avg = calculate.calculate_eng_avg(students)

math_avg = calculate.calculate_math_avg(students)

 

printed.print_student(students)

print()

printed.print_class(class_avg, kor_avg, eng_avg, math_avg)

 

[calculate]

 

def calculate_total(students):

for student in students:

student["total"] = student["kor"] + student["eng"] + student["math"]

 

def calculate_average(students):

for student in students:

student["avg"] = student["total"] / len(students)

def calculate_order(students):

temp_students = sorted(students, key=lambda x: x["total"], reverse=True)

order = 1

for student in temp_students:

student["order"] = order

order = order + 1

 

return temp_students

 

def calculate_class_avg(students):

class_total = 0

 

for student in students:

class_total = class_total + student["total"]

 

return class_total / len(students)

 

def calculate_kor_avg(students):

kor_total = 0

 

for student in students:

kor_total = kor_total + student["kor"]

 

return kor_total / len(students)

 

def calculate_eng_avg(students):

eng_total = 0

 

for student in students:

eng_total = eng_total + student["eng"]

 

return eng_total / len(students)

 

def calculate_math_avg(students):

math_total = 0

 

for student in students:

math_total = math_total + student["math"]

 

return math_total / len(students)

 

[printed]

 

def print_student(students):

for student in students:

print("번호: %s, 이름: %s, 국어: %d, 영어: %d, 수학: %d, 총점: %d,

평균: %.2f,등수: %d" % (

student["num"], student["name"], student["kor"], student["eng"],

student["math"], student["total"],

student["avg"], student["order"]))

 

def print_class(class_avg, kor_avg, eng_avg, math_avg):

print("반 평균: %.2f" % class_avg)

print("국어 평균: %.2f" % kor_avg)

print("영어 평균: %.2f" % eng_avg)

print("수학 평균: %.2f" % math_avg)

 

calculate 연산 및 출력 하는 함수 모듈 포함하는 별도의 메인 코드를 구현하여

실행하면 다음과 같이 출력 결과를 확인할 수 있다.

 

[main]

##cal_main 모듈안에 계산(calculate연산 및 출력 하는 함수 모듈 포함 ##

import cal_main

 

a = cal_main.main()

 

print(a)

 

 

 

[네 번째 방법]

다음과 같이 하나의 코드로 구현할 수 있다.

 

def calculate_total(students):

for student in students:

student["total"] = student["kor"] + student["eng"] + student["math"]

 

def calculate_average(students):

for student in students:

student["avg"] = student["total"] / len(students)

 

def calculate_order(students):

temp_students = sorted(students, key=lambda x: x["total"], reverse=True)

order = 1

for student in temp_students:

student["order"] = order

order = order + 1

 

return temp_students

 

def calculate_class_avg(students):

class_total = 0

for student in students:

class_total = class_total + student["total"]

return (class_total / len(students))

 

def calculate_kor_avg(students):

kor_total = 0

for student in students:

kor_total = kor_total + student["kor"]

return (kor_total / len(students))

 

def calculate_math_avg(students):

math_total = 0

for student in students:

math_total = math_total + student["math"]

return (math_total / len(students))

 

def calculate_eng_avg(students):

eng_total = 0

for student in students:

eng_total = eng_total + student["eng"]

return (eng_total / len(students))

 

def print_student(students):

for student in students:

print("번호 : %s, 이름: %s, 국어: %d, 영어: %d, 수학: %d, 총점: %d,

평균 %.2f, 등수: %d" % (student["num"], student["name"],

student["kor"], student["eng"], student["math"],

student["total"],student["eng"], student["order"]))

 

 

def print_class(class_avg, kor_avg, eng_avg, math_avg):

print("반 평균 : %.2f" % class_avg)

print("국어 평균: %.2f" % kor_avg)

print("영어 평균: %.2f" % eng_avg)

print("수학 평균: %.2f" % math_avg)

 

 

def main():

students = [{"num": "1", "name": "김민규", "kor": 90, "eng": 80, "math":

85, "total": 0.0, "order": 0}, {"num": "2", "name": "김용학

", "kor": 90, "eng": 85, "math": 90, "total": 0.0, "order":

0}, {"num": "3", "name": "박영철", "kor": 80, "eng": 80,

"math": 80, "total": 0.0, "order": 0}]

 

class_avg = 0.0

kor_avg = 0.0

eng_avg = 0.0

math_avg = 0.0

 

calculate_total(students)

calculate_average(students)

students = calculate_order(students)

 

class_avg = calculate_class_avg(students)

kor_avg = calculate_kor_avg(students)

eng_avg = calculate_eng_avg(students)

math_avg = calculate_math_avg(students)

 

print_student(students)

print()

print_class(class_avg, kor_avg, eng_avg, math_avg)

 

if __name__ == "__main__":

main()

 

 

 

 

 

728x90
반응형

'Language > Python' 카테고리의 다른 글

파이썬을 활용한 웹 크롤링_기본편  (0) 2020.02.26
Python에서 Excel 사용  (0) 2020.02.26
파이썬 -제어문  (0) 2020.02.26
python 소개  (0) 2020.02.26
os.walk : 하위 디렉터리 검색을 쉽게 해주는  (0) 2020.02.26