10. 함수

함수는 재사용 가능한 프로그램 조각을 말합니다. 이것은 특정 블록의 명령어 덩어리를 묶어 이름을 짓고, 그 이름을 프로그램 어디에서든 사용함으로써 그 블록에 포함된 명령어를 몇 번이고 다시 실행할 수 있게 해 줍니다. 이를 보고 '함수를 호출한다'라고 합니다. 사실 우리는 이미 앞에서 len이나 range와 같은 많은 내장 함수를 사용해 왔습니다.

함수는 프로그램을 작성할 때 아마도 가장 중요한 단위가 될 것입니다(어떤 프로그래밍 언어에서라도). 따라서 이 장에서는 함수라는 것을 다양한 관점에서 살펴보겠습니다.

함수는 def 키워드를 통해 정의됩니다. def 뒤에는 함수의 식별자 이름을 입력하고, 괄호로 감싸여진 함수에서 사용될 인자arguments 목록을 입력하며, 마지막으로 콜론을 입력하면 함수의 정의가 끝납니다. 새로운 블록이 시작되는 다음 줄부터는 이 함수에서 사용될 명령어를 입력합니다. 복잡해 보이지만, 다음 예제를 통해 함수를 정의하는 것이 얼마나 간단한지 알아봅시다.


https://github.com/swaroopch/byte-of-python/blob/master/programs/function1.py

def say_hello():
    # block belonging to the function
    print 'hello world'
# End of function

say_hello() # call the function
say_hello() # call the function again
function1.py(이 코드를 function1.py로 저장하세요)

실행 결과는 다음과 같습니다.

$ python function1.py
hello world
hello world


여기에서는 앞서 설명한 문법을 이용하여 say_hello라는 함수를 정의했습니다. 이 함수는 어떤 인자도 넘겨받지 않으므로, 괄호 내에 매개 변수를 정의하지 않습니다. 함수의 인수란 함수로 넘겨지는 입력값을 말하며, 함수는 이 값을 처리하여 결과를 넘겨줍니다.

함수를 두 번 호출하는 것은 같은 코드를 두 번 작성하는 것과 같은 효과를 가진다는 것을 알아두세요.


10.1 함수와 매개 변수

함수를 정의할 때 매개 변수를 지정할 수도 있습니다. 매개 변수란 함수로 넘겨지는 값을 말하며, 함수는 이 값들을 이용해 무언가를  수 있습니다. 매개 변수는 변수와 거의 같이 취급되지만, 매개 변수의 값은 함수가 호출될 때 넘겨받은 값으로 채워지며 함수가 실행되는 시점에서는 이미 할당이 완료되어 있다는 점이 다릅니다.

매개 변수는 함수를 정의할 때 괄호 안에 쉼표로 구분하여 지정합니다. 함수를 호출할 때에는, 동일한 방법으로 함수에 값을 넘겨 줍니다. 함수를 정의할 때 주어진 이름을 매개 변수라 부르고, 함수에 넘겨준 값을 인자라 부릅니다.


https://github.com/swaroopch/byte-of-python/blob/master/programs/function_param.py

def print_max(a, b):
    if a > b:
        print a, 'is maximum'
    elif a == b:
        print a, 'is equal to', b
    else:
        print b, 'is maximum'

# directly pass literal values
print_max(3, 4)

x = 5
y = 7

# pass variables as arguments
print_max(x, y)
function_param.py(이 코드를 function_param.py로 저장하세요)

실행 결과는 다음과 같습니다.

$ python function_param.py

4 is maximum
7 is maximum


여기서는 두 매개 변수 a와 b를 사용하는 print_max라는 함수를 정의합니다. 그리고 간단한 if…​else 문을 이용하여 크기를 비교하고 둘 중에 더 큰 값을 출력합니다.

print_max 함수를 처음 호출할 때에는 값을 직접 인자로 입력하여 넘겨주었습니다. 반면 두 번째 호출시에는 변수를 인자로 입력했습니다. 이것은 print_max(x, y)는 변수 x에 지정된 값을 변수 a에 입력하고 변수 y의 값을 변수 b에 입력한다는 의미입니다. 따라서 이 함수는 두 경우 모두 동일하게 동작합니다.


10.2 지역 변수

여러분이 정의한 함수 안에서 변수를 선언하고 사용할 경우, 함수 밖에 있는 같은 이름의 변수와 함수 안에 있는 변수는 서로 관련이 없습니다. 함수 안에 선언된 변수를 함수의 지역local 변수라고 하며, 그 범위를 변수의 스코프scope라고 부릅니다. 모든 변수는 변수가 정의되는 시점에서의 블록을 스코프로 가지게 됩니다.


https://github.com/swaroopch/byte-of-python/blob/master/programs/function_local.py

x = 50

def func(x):
    print 'x is', x
    x = 2
    print 'Changed local x to', x

func(x)
print 'x is still', x
function_local.py(이 코드를 function_local.py로 저장하세요)

실행 결과는 다음과 같습니다.

$ python function_local.py
x is 50
Changed local x to 2
x is still 50


먼저 함수의 첫번째 줄에서 x라는 이름을 가진 변수에 담긴 '값'을 출력합니다. 이때 함수 정의 위에 정의된 변수의 값을 함수의 매개 변수 x로 넘겨받은 값이 출력됩니다.

다음으로, x에 값 2를 대입합니다. 그러나 x는 함수의 지역 변수이므로, 함수 안에서 x의 값이 대입된 값으로 변하는 반면, 메인 블록의 x는 변하지 않고 그대로 남아 있습니다.

프로그램에서 사용된 마지막 print 문을 통해 메인 블록의 x 값을 출력해 보면, 그 이전에 호출된 함수 안에서 시행된 지역 변수값의 변화가 적용되지 않았음을 확인할 수 있습니다.


10.3 global 문

함수나 클래스 내부에서 상위 블록에 선언된 변수의 값을 변경하고 싶을 경우, 파이썬에게 이 변수를 앞으로 지역 변수가 아닌 전역global 변수로 사용할 것임을 알려주어야 합니다. 이때 필요한 게 global 문입니다. global 문을 사용하지 않으면, 함수 외부에서 선언된 변수의 값을 함수 내부에서 변경할 수 없습니다.

함수 안에서 동일한 이름으로 선언된 변수가 없을 경우, 함수 밖의 변수값을 함수 안에서 읽고 변경할 수도 있습니다. 그러나, 이것은 프로그램을 읽을 때 변수가 어디서 어떻게 선언되었는지 파악하기 힘들게 만들기 때문에 추천할만한 방법이 아니며, 가능한 이런 경우를 피하기 바랍니다. global 문을 사용하면 그 블록의 밖에서 그 변수가 선언되어 있음을 알려주므로 프로그램이 좀 더 명확해집니다.


https://github.com/swaroopch/byte-of-python/blob/master/programs/function_global.py

x = 50

def func():
    global x

    print 'x is', x
    x = 2
    print 'Changed global x to', x

func()
print 'Value of x is', x
function_global.py(이 코드를 function_global.py로 저장하세요)

실행 결과는 다음과 같습니다.

$ python function_global.py
x is 50
Changed global x to 2
Value of x is 2


global 문을 통해 x가 전역 변수임을 파이썬에게 알려줍니다. 따라서, 이후로 x에 값을 대입하면 메인 블록의 x 값 또한 변경됩니다.

하나의 global 문으로 여러 개의 전역 변수를 동시에 지정할 수도 있습니다. global x, y, z와 같이 하면 됩니다.


10.4 기본 인수값

어떤 특별한 경우, 함수를 호출할 때 인수를 선택적으로 넘겨주게 하여 사용자가 값을 넘겨주지 않으면 자동으로 기본값을 사용하도록 구현해야 할 때가 있습니다. 이 경우, 기본 인수값을 지정하면 됩니다. 함수를 선언할 때 원하는 매개 변수 뒤에 대입 연산자 (=)와 기본값을 입력하여 기본 인수값을 지정합니다.

이때, 기본 인수값은 반드시 상수여야 합니다. 좀 더 정확히 말하자면, 불변값이어야 합니다. 불변값에 대해서는 차후에 다룰 것입니다. 일단 지금은, 그래야 한다는 것만 기억하기 바랍니다.


https://github.com/swaroopch/byte-of-python/blob/master/programs/function_default.py

def say(message, times=1):
    print message * times

say('Hello')
say('World', 5)
function_default.py(이 코드를 function_default.py로 저장하세요)


$ python function_default.py
Hello
WorldWorldWorldWorldWorld


함수 say는 지정된 숫자 만큼 문자열을 반복하여 출력하는 합수입니다. 숫자를 지정하지 않으면, 기본값이 적용되어, 문자열이 한 번 출력됩니다. 이 결과는 매개 변수 times 의 기본 인수값을 1로 지정해 줌으로써 얻어집니다.

프로그램에서 처음 say를 호출할 때에는 함수에 문자열만 넘겨주어 한번만 출력합니다. 두 번째 호출에서는 문자열과 인수 5를 넘겨줘 함수가 문자열을 5번 반복하여 말(say)하게 합니다.


CAUTION

매개 변수 목록에서 마지막에 있는 매개 변수들에만 기본 인수값을 지정할 수 있습니다. 기본 인수값을 지정하지 않은 매개 변수의 앞에 위치한 매개 변수에만 기본 인수값을 지정할 수 없습니다.

이것은 함수를 호출할 때 매개 변수의 위치에 맞춰서 값이 지정되기 때문입니다. 예를 들어, def func(a, b=5는 옳은 함수 정의이지만 def func(a=5, b)는 옳지 않습니다.



10.5 키워드 인수

여러 개의 매개 변수를 가지고 있는 함수를 호출할 때, 그중 몇 개만 인수를 넘겨주고 싶을 때가 있습니다. 이때 매개 변수의 이름을 지정하여 직접 값을 넘겨줄 수 있는데 이것을 키워드 인수라 부릅니다. 함수 선언 시 지정된 매개 변수의 순서대로 값을 넘겨주는 것 대신, 매개 변수의 이름(키워드)을 사용하여 각각의 매개 변수에 인수를 넘기도록 지정합니다.

키워드 인수는 두 가지 장점을 가지고 있습니다. 첫째, 인수의 순서를 신경쓰지 않고도 함수를 쉽게 호출할 수 있습니다. 둘째, 특정한 매개 변수에만 값을 넘기도록 하여 나머지는 자동으로 기본 인수값으로 채워지게 할 수 있습니다.


https://github.com/swaroopch/byte-of-python/blob/master/programs/function_keyword.py

def func(a, b=5, c=10):
    print 'a is', a, 'and b is', b, 'and c is', c

func(3, 7)
func(25, c=24)
func(c=50, a=100)
function_keyword.py(이 코드를 function_keyword.py로 저장하세요)

실행 결과는 다음과 같습니다.

$ python function_keyword.py
a is 3 and b is 7 and c is 10
a is 25 and b is 5 and c is 24
a is 100 and b is 5 and c is 50


앞의 코드에서 func라 이름 지어진 함수는 기본 인수값이 지정되지 않은 한 개의 매개 변수와, 기본 인수값이 지정된 두 개의 매개 변수, 총 세 개의 매개 변수를 가지고 있습니다.

첫 번째 호출 func(3, 7)에서, 매개 변수 a는 값 3, 매개 변수 b는 7을 넘겨 받으며, c에는 기본 인수값 10이 주어집니다.

두 번째 호출 func(25, c=24)에서는, 첫 번째 인수인 25가 변수 a에 넘겨집니다. 그리고 매개 변수 c는 키워드 인수를 통해 값 24가 지정되며, 변수 b에는 기본값 5가 주어집니다.

세 번째 호출 func(c=50, a=100)에서는, 모든 값을 지정하는 데 키워드 인수가 사용됩니다. 함수 정의에는 a 다음에 c가 정의되어 있지만, 키워드 인수를 사용하면 그 순서에 상관없이 c를 먼저 지정하고 a를 나중에 지정할 수도 있습니다.


10.6 VarArgs 매개 변수

가끔 함수에 임의의 개수의 매개 변수를 지정해야 한다면 어떻게 해야 할까요? 이때 VarArgs 매개 변수를 사용합니다. 다음 예제와 같이 별 기호를 사용하여 임의의Variable 개수의 인수Arguments를 표현합니다.


https://github.com/swaroopch/byte-of-python/blob/master/programs/function_varargs.py

def total(initial=5, *numbers, **keywords):
    count = initial
    for number in numbers:
        count += number
    for key in keywords:
        count += keywords[key]
    return count

print total(10, 1, 2, 3, vegetables=50, fruits=100)
function_varargs.py(이 코드를 function_varargs.py로 저장하세요)


$ python function_varargs.py
166


앞에 별 기호가 달린 매개 변수, 예를 들어 *param과 같이 매개 변수를 지정하면 함수에 넘겨진 모든 위치 기반 인수가 param 이라는 이름의 튜플로 묶여서 넘어옵니다.

또 이와 비슷하게 앞에 별 두 개가 달린 매개 변수, 예를 들어 **param과 같이 매개 변수를 지정하면 함수에 넘겨진 모든 키워드 인수가 param이라는 이름의 사전으로 묶여서 넘어옵니다.

튜플과 사전에 대해서는 이후 장에서 좀 더 자세히 다뤄봅니다.


10.7 return 문

return 문은 함수로부터 되돌아(return) 나올 때, 즉 함수를 빠져 나올 때 사용됩니다. 이때 return 값처럼 값을 지정하면, 함수가 종료될 때 그 값을 반환합니다.


https://github.com/swaroopch/byte-of-python/blob/master/programs/function_return.py

def maximum(x, y):
    if x > y:
        return x
    elif x == y:
        return 'The numbers are equal'
    else:
        return y

print maximum(2, 3)
function_return.py(이 코드를 function_return.py로 저장하세요)

실행 결과는 다음과 같습니다.

$ python function_return.py
3


여기에서 사용된 maximum 함수는 매개 변수 중 최댓값을 반환합니다. 앞의 코드에서는 함수에 넘겨진 숫자들 중 최댓값을 반환합니다. 간단한 if..else 구문을 통해 더 큰 값을 찾고, 최종 값을 반환(return)합니다.

return 문 뒤에 아무 값도 지정하지 않는 경우, return None을 실행하는 것과 같습니다. None 이란 파이썬에서 사용되는 특별한 형식으로 아무 것도 없음을 의미합니다. 예를 들면, 어떤 변수의 값이 None이라는 것은 변수에 할당된 값이 없음을 의미합니다.

여러분이 return 문을 함수에 지정하지 않으면, 함수는 끝날 때 자동으로 return None 구문을 암시적으로 호출합니다. 다음 예제에서 return 문이 지정되지 않은 some_function이라는 함수를 선언하고 print some_function()을 실행하여 그 결과를 확인해 보기 바랍니다.

def some_function():
    pass

 

pass 문은 아무 기능이 없는 구문입니다. 이것은 빈 블록을 지정할 때 사용됩니다. 


TIP

사실 파이썬에는 '최댓값을 찾는' 내장 함수 max가 이미 포함되어 있습니다. 따라서 가능하면 이 내장 함수를 사용하시기 바랍니다.



10.8 DocString

파이썬은 설명 문자열Documentation String이라고 불리우는, 짧게 줄여서 DocStrings라 불리우는 편리한 기능을 제공합니다. DocString은 여러분이 만든 프로그램을 알아보기 쉽게 해 주고, 또 나중에 프로그램에 대한 설명서를 작성할 때 유용한 도구입니다. 다음 예제와 같이, DocString은 프로그램이 실행 중일 때도 읽을 수 있습니다.


https://github.com/swaroopch/byte-of-python/blob/master/programs/function_docstring.py

def print_max(x, y):
    '''Prints the maximum of two numbers.

    The two values must be integers.'''
    # convert to integers, if possible
    x = int(x)
    y = int(y)

    if x > y:
        print x, 'is maximum'
    else:
        print y, 'is maximum'

print_max(3, 5)
print print_max.__doc__
function_docstring.py(이 코드를 function_docstring.py로 저장하세요)

실행 결과는 다음과 같습니다.

$ python function_docstring.py
5 is maximum
Prints the maximum of two numbers.

    The two values must be integers.


함수에 포함된 첫 논리적 명령행에 적어둔 문자열은 함수의 DocString 이라고 불리우는 것입니다. 여기에서 설명하는 DocString은 모듈과 클래스에도 똑같이 적용됩니다. 각각에 대해서는 각 장에서 좀 더 자세히 알아봅니다.

DocString은 일반적으로 첫째 줄의 첫 문자는 대문자로, 마지막 문자는 마침표로 끝나도록 작성합니다. 그리고 두번째 줄은 비워두고, 세번째 줄부터는 어떤 기능을 하는지를 상세하게 작성합니다. 저는 앞으로 여러분이 함수의 DocString를 작성할 때 이 규칙을 따르기를 강력히 권합니다.

print_max 함수의 DocString은 함수의 doc 속성을 통해 접근할 수 있습니다 (밑줄이 두 개임을 다시 한번 확인하세요). doc은 함수 객체가 갖고 있는 기본 속성입니다. 파이썬에서는 함수를 포함한 모든 것이 객체로 다루어진다는 점을 기억하세요. 이에 대해서는 클래스 장에서 좀 더 자세히 알아볼 것입니다.

파이썬에서 help()를 이용해 보았다면, 여러분은 이미 DocString을 본 적이 있는 것입니다! help()가 하는 일은 주어진 대상의 doc 속성을 가져와 화면에 보여주는 것뿐입니다. 따라서 앞서 만든 함수에 대해서도 마찬가지로 동작합니다. 여러분의 프로그램에 help(print_max)라고 한 줄 추가해 보기 바랍니다. help 창을 닫으려면 q 키를 누르세요.

이를 이용하여 여러분의 프로그램에 대한 명세서를 자동으로 만들어주는 프로그램들이 있습니다. 따라서, 저는 여러분이 어떤 함수를 작성하시던지 DocString을 작성할 것을 강력히 권합니다. 파이썬과 함께 설치되는 pydoc 또한 help()와 비슷한 방법으로 DocString을 이용하여 동작합니다.


10.9 요약

지금까지 함수에 대해 많은 것들을 알아 보았습니다만, 사실 아직 모든 기능을 다 알아본 것은 아닙니다. 그러나, 자주 사용되는 기능에 대해서는 거의 모든 것을 설명해 드렸기 때문에 아마 앞으로 매일매일 프로그램을 작성할 때는 별 무리가 없을 것입니다.

다음 장에서는 모듈을 작성하고 사용하는 방법에 대해 알아보도록 하겠습니다.