파이썬(Python) 기초 - 함수

170831

이제 함수, 입력과 출력, 파일 처리 방법에 대해 알아보자. 프로그램이 어떻게 동작할 지 설계할 때, 입출력의 설계가 중요하다. 특정 프로그램만이 사용하는 함수인지, 모든 프로그램이 공통으로 사용하는 함수인지, 오픈 API로 공개하여 외부 프로그램들도 사용할 수 있는 건지 잘 생각하자.


함수

함수는 입력값을 가지고 어떤 일을 수행한 다음에 그 결과물을 내어놓는 것을 말한다. 즉, 반복되는 부분이 있을 경우 “반복적으로 사용되는 가치 있는 부분”을 하나로 묶어서 “어떤 입력값을 주었을 때 어떤 결과값을 돌려준다”라는 식의 함수로 작성할 수 있다.

파이썬 함수 기본 구조는 다음과 같다.

def 함수명(입력 인수):
    <수행할 문장1>
    <수행할 문장2>
    ...
    return 결과값

def는 함수를 만들 때 사용하는 예약어이며, 함수명은 함수를 만드는 사람이 임의로 만들 수 있다. 함수를 정의한 다음 if, while, for문 등과 마찬가지로 함수에서 수행할 문장을 입력하면 끝!

>>> def sum(a, b):
...     result = a + b
...     return result
...
>>> a = 3
>>> b = 4
>>> c = sum(a, b)
>>> print(c)
7
>>> a = sum(3, 4)
>>> print(a)
7

입력값을 함수의 인수, 입력 인수 등으로 말하기도 하고, 결과값을 출력값, 리턴값, 돌려주는 값 등으로 말하니 이 점에 유의하자.

입력값이 없는 함수도 존재한다. 아래를 보자.

>>> def say():
...     return 'Hi'
...
>>> a = say()
>>> print(a)
Hi

위 함수를 쓰기 위해서는 say()처럼 괄호 안에 아무런 값도 넣지 않아야 한다. 그렇다면 이번에는 결과값이 없는 함수에 대해 알아 보자.

>>> def sum(a, b):
...     print("%d, %d의 합은 %d입니다." % (a, b, a+b))
...
>>> sum(3, 4)
3, 4 합은 7입니다.

결과값이 없는 함수는 호출해도 돌려주는 값이 없기 때문에 바로 함수명을 입력해서 사용한다. 여기서 print문은 함수의 구성 요소 중 하나인 <수행할 문장="">에 해당하는 부분일 뿐, 결과값은 오직 return 명령어로만 받을 수 있다. 주의하자!

돌려받는 값을 a라는 변수에 대입하여 출력하면 결과값이 있는지 없는지 알 수 있다.

>>> a = sum(3, 4)
>>> print(a)
None

None이란 거짓을 나타내는 자료형이다.

입력값도 결과값도 없는 함수도 있다.

>>> def say():
...     print('Hi')
...
>>> say()
Hi

입력 인수를 받는 것도 없고 return문도 없으니 입력값도 결과값도 없는 함수다. 사용하는 방법은 함수명을 입력하는 방법 밖에 없다.

입력값이 여러 개라면, 몇 개가 될지 모를 때는 어떻게 해야 할까?

def 함수이름(*입력변수):
    <수행할 문장>
    ...

일반적으로, 여러 개의 입력값을 받는 함수를 만들면 입력 인수 부분을 *입력인수로 바꿔서 사용한다. 입력 인수가 몇 개가 됐든 모두 더해 주는 예를 보자.

>>> def sum_many(*args):
...     sum = 0
...     for i in args:
...         sum = sum + i
...     return sum
...
>>>

위 예제에서 *args처럼 입력 변수명 앞에 *을 붙이면 입력값들을 모아 튜플로 만들어 준다. 여기서 *args는 임의로 정한 변수명이고, 사실 *pey, *python처럼 아무 이름이나 써도 된다. (args는 입력 인수를 뜻하는 arguments의 약자다.)

>>> def sum_mul(choice, *args):
...     if choice == "sum":
...         result = 0
...         for i in args:
...             result = result + i
...     elif choice == "mul":
...         result = 1
...         for i in args:
...             result = result * i
...     return result
...
>>>

위의 예제에서는 입력 인수로 choice와 *args를 받는다. 그렇다면, 해당 문자열의 입력 인수에 따라 result를 다르게 할 수 있게 된다. 하지만, 명심하자. 함수의 결과값은 언제나 하나이다!

아래 예를 살펴 보자.

>>> def sum_and_mul(a,b):
...     return a+b, a*b
>>> result = sum_and_mul(3,4)
>>> a = result
>>> print(a)
(7, 12)

함수의 결과값은 언제나 1개라서 sum_and_mul 함수의 결과값 a+ba*b는 튜플값 하나인 (a+b, a*b)로 돌려준다. 그렇다고 해서 return문을 2개 만들어서 값을 돌려줄 수 없다. 즉, 함수는 return문을 만나는 순간 결과값을 돌려준 다음 함수를 빠져나가게 된다.

그래서 특정 상황에서 return을 단독으로 사용해서 함수를 즉시 빠져나갈 수 있다. 아래 예를 보자.

>>> def say_nick(nick):
...     if nick == "바보":
...         return
...     print("나의 별명은 %s 입니다." % nick)
...
>>>

위 예제의 함수는 리턴값이 없다(문자열을 출력하는 것과 리턴값이 있다는 건 전혀 다르다). 그래서 만약에 입력값으로 “바보”라는 값이 들어오면 문자열을 출력하지 않고 함수를 즉시 빠져나간다.

이번에는 함수의 인수를 전달할 때, 입력 인수에 초깃값을 미리 설정해 보자. 함수의 입력 인수에 들어갈 값이 항상 변하는 것이 아닐 경우에는 유용하다. 초깃값을 설정해도 입력 인수로 따로 값을 주면 그 값이 들어가니 편리하다.

def say_myself(name, old, man=True):
    print("나의 이름은 %s 입니다." % name)
    print("나이는 %d살입니다." % old)
    if man:
        print("남자입니다.")
    else:
        print("여자입니다.")

하지만, 만약에 def say_myself(name, man=True, old)라고 했을 때, 함수를 실행하면 오류가 난다. 파이썬 인터프리터는 입력값을 man 변수와 old 변수 중 어느 곳에 대입해야 할지 알 수 없기 때문이다. 에러를 읽어보면, 초기화시키고 싶은 입력 변수들은 항상 뒤쪽에 위치시켜야하는 것을 알 수 있다.

함수 안에서 사용할 변수 이름을 함수 밖에서도 동일하게 사용한다면? 아래 예를 보자.

a = 1
def vartest(a):
    a = a +1

vartest(a)
print(a)

위 예제를 실행하면 1이 나온다. 왜냐하면, 함수 안에서 새로 만들어진 변수(a)는 함수 안에서만 사용되는 “함수만의 변수”이기 때문이다. 즉, def vartest(a)에서 입력 인수를 뜻하는 변수 a는 함수 안에서만 사용되는 변수이지 함수 밖의 변수 a가 아니다.

def vartest(a):
    a = a + 1

vartest(3)
print(a)

위 코드를 실행하면 당연히 에러가 난다. 왜냐하면 함수 밖에서 a라는 변수를 어디에서도 찾을 수 없기 때문이다. 함수 안에서 선언된 변수는 함수 안에서만 사용될 뿐 함수 밖에서는 사용되지 않는다.

그렇다면, vartest라는 함수를 이용해서 함수 밖의 변수 a를 1만큼 증가시킬 수 있는 방법은 뭘까? 여기엔 2가지 방법이 있다.

1. return 이용하기

a = 1
def vartest(a):
    a = a +1
    return a

a = vartest(a)
print(a)

a = vartest(a)라고 대입하면 a가 vartest 함수의 결과값으로 바뀐다. 물론 vartest 함수 안의 a 변수는 함수 밖의 a와는 다른 것이다.

2. global 명령어 이용하기

a = 1
def vartest():
    global a
    a = a+1

vartest()
print(a)

vartest 함수 안의 global a라는 문장은 함수 안에서 함수 밖의 a 변수를 직접 사용하겠다는 뜻이다. 하지만, 함수는 독립적으로 존재하는 것이 좋기 때문에 외부 변수에 종속적인 함수는 그다지 좋은 함수가 아니다.