함수

함수는 재사용 가능한 프로그램 조각입니다. 함수를 이용하면 문장 블록에 이름을 지정해 프로그램의 어느 곳에서든 그 이름으로 몇 번이고 해당 블록을 실행할 수 있습니다. 이를 가리켜 함수 호출(call)이라고 합니다. 이미 앞에서 len이나 range 같은 파이썬에 내장된 함수를 사용한 바 있습니다.

함수라는 개념은 아마 어느 정도 규모가 있는 소프트웨어(어떤 언어로 작성된 것이든)에서 가장 중요한 구성 요소일 것입니다. 그래서 이번 장에서는 함수의 다양한 측면을 살펴보려고 합니다.

함수는 def 키워드를 이용해 정의합니다. 이 키워드 다음에 함수의 식별자 이름이 오고, 한 쌍의 괄호가 나온 후에(경우에 따라 이 안에 여러 개의 변수명을 두기도 합니다) 마지막으로 줄 끝에 콜론을 둡니다. 그다음으로 이 함수의 본문에 해당하는 문장 블록이 옵니다. 다음 예제를 보면 지금까지 설명한 내용이 실제로는 매우 간단하다는 사실을 알 수 있습니다.

예제(function1.py):

def say_hello():
    # 함수에 속하는 블록
    print('hello world')
# 함수 종료

say_hello()  # 함수를 호출
say_hello()  # 함수를 다시 호출

출력 결과:

$ python function1.py
hello world
hello world

동작 원리

앞에서 설명한 구문을 이용해 say_hello라는 함수를 정의합니다. 이 함수는 매개변수(parameter)를 받지 않으므로 괄호 안에 아무런 변수도 선언하지 않습니다. 함수의 매개변수는 함수에 각기 다른 값을 전달하고 그에 따른 결과를 받을 수 있도록 함수에 전달하는 입력값입니다.

같은 함수를 두 번 호출할 수 있는데, 이는 같은 코드를 재차 작성할 필요가 없다는 뜻입니다.

함수 매개변수

함수는 매개변수를 받을 수 있는데, 전달된 매개변수 값을 활용해 뭔가를 수행할 수 있습니다. 매개변수는 함수를 호출할 때 값이 정의되고 함수가 실행될 때는 값이 이미 할당돼 있다는 점을 제외하면 변수와 흡사합니다.

매개변수는 함수를 정의할 때 작성한 괄호 쌍 안에 콤마로 분리해서 지정합니다. 함수를 호출할 때 같은 방식으로 값을 전달합니다. 여기서 사용한 용어에 주의할 필요가 있는데, 함수를 정의할 때 부여한 이름을 매개변수(parameter)라 하고, 함수를 호출할 때 전달하는 값을 인수(argument)라고 합니다.

예제(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')

# 리터럴 값을 직접 전달
print_max(3, 4)

x = 5
y = 7

# 변수를 인수로 전달
print_max(x, y)

출력 결과:

$ python function_param.py
4 is maximum
7 is maximum

동작 원리

여기서는 ab라는 두 개의 매개변수를 사용하는 print_max 함수를 정의합니다. 함수에서는 간단한 if..else 문을 사용해 어느 숫자가 더 큰지 확인한 후 큰 숫자를 출력합니다.

print_max 함수를 처음으로 호출할 때는 숫자를 곧바로 인수로 전달합니다. 두 번째로 호출할 때는 변수를 인수로 전달해 함수를 호출합니다. print_max(x, y)에서는 인수 x의 값이 매개변수 a에 할당되고, 인수 y의 값은 매개변수 b에 할당됩니다. print_max 함수는 두 경우에 모두 동일하게 동작합니다.

지역 변수

함수 정의부에 변수를 선언할 때 해당 변수들은 함수 바깥에서 같은 이름으로 사용되는 다른 어떤 변수와도 아무 관계가 없습니다. 즉, 변수명은 함수에 국한(local)됩니다. 이를 변수의 유효범위(scope)라고 합니다. 모든 변수는 해당 변수가 선언된 블록(변수의 이름을 정의한 지점부터 시작하는)에 해당하는 유효범위를 갖습니다.

예제(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)

출력 결과:

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

동작 원리

함수 본문의 첫 줄에서 x라는 이름의 을 처음으로 출력할 때 파이썬은 메인 블록에 선언된, 즉 함수 정의 위에 위치한 매개변수의 값을 사용합니다.

다음으로 x에 값 2를 할당합니다. x라는 이름은 함수에 국한됩니다. 따라서 함수 안에서 x의 값을 변경하면 메인 블록에 정의된 x는 영향을 받지 않은 채로 유지됩니다.

마지막 print 문에서는 메인 블록에 정의된 x의 값을 출력하는데, 이를 통해 앞에서 호출한 함수 안에서 지역적으로 값을 할당하더라도 여기에 영향을 받지 않다는 것을 확인할 수 있습니다.

global

프로그램의 최상위 수준(즉, 함수나 클래스 등의 어떠한 유효범위에도 속하지 않는)에서 정의한 이름에 값을 할당하고 싶다면 그 이름이 지역 범위가 아닌 전역 범위(global)에 속한다고 파이썬에게 알려줘야 합니다. 이때 global 문을 하면 됩니다. global 문을 사용하지 않고는 함수 바깥에 정의된 변수에 값을 할당할 수 없습니다.

함수 안에 같은 이름의 변수가 없다는 가정하에 함수 바깥에서 정의된 변수의 값을 사용할 수 있습니다. 하지만 이것은 권장하지 않고 도리어 지양해야 할 방법인데, 프로그램 코드를 읽는 사람 입장에서 변수가 어디에서 정의됐는지 파악하기가 어려워지기 때문입니다. global 문을 사용하면 변수가 가장 바깥쪽 블록에서 정의됐다는 사실이 충분히 명확해집니다.

예제(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)

출력 결과:

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

동작 원리

global 문은 x가 전역 변수(global variable)라는 사실을 선언하는 데 사용됩니다. 따라서 함수 안에서 x에 값을 할당하면 메인 블록에서 x의 값을 사용할 때 그러한 변경 사항이 반영됩니다.

global 문에서 하나 이상의 전역 변수를 지정할 수 있습니다(예: global x, y, z).

기본 인수 값

어떤 함수에서는 특정 매개변수를 선택사항으로 만들어 사용자가 해당 매개변수에 값을 전달하고 싶지 않을 때 기본값을 사용하고 싶을 수 있습니다. 이때 기본 인수 값을 사용하면 됩니다. 함수 정의부의 매개변수명에 할당 연산자(=)와 기본값을 추가해 기본 인수 값을 지정할 수 있습니다.

기본 인수 값은 상수여야 한다는 점에 주의합니다. 좀 더 정확하게 말하자면 기본 인수 값은 불변값이어야 합니다. 이 부분에 대해서는 이후 장에서 자세히 설명하겠습니다. 지금 당장은 그것만 기억하세요.

예제(function_default.py):

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

say('Hello')
say('World', 5)

출력 결과:

$ python function_default.py
Hello
WorldWorldWorldWorldWorld

동작 원리

say 함수는 지정한 횟수만큼 문자열을 출력합니다. 함수에 값을 전달하지 않으면 기본적으로 문자열은 딱 한 번만 출력되는데, times 매개변수에 1이라는 기본 인수 값을 지정해 이를 처리했습니다.

say를 처음 사용할 때는 문자열만 전달해서 해당 문자열이 한 번만 출력됩니다. 두 번째로 say를 사용할 때는 문자열과 인수 5를 함께 전달해서 문자열 메시지를 5번 출력하게 합니다.

경고

매개변수 목록에서 맨 끝에 있는 매개변수에만 기본 인수 값을 줄 수 있습니다. 즉, 함수의 매개변수 목록에서 기본 인수 값이 없는 매개변수 앞에 기본 인수 값을 지정한 매개변수를 둘 수 없습니다.

이렇게 해야 하는 이유는 인수 값이 위치를 토대로 매개변수에 할당되기 때문입니다. 예를 들어, def func(a, b=5)는 유효하지만 def func(a=5, b)그렇지 않습니다.

키워드 인수

어떤 함수의 매개변수가 여러 개이고 그중 하나만 지정하고 싶다면 매개변수명을 통해 매개변수의 값을 전달할 수 있습니다. 이를 키워드 인수(keyword argument)라고 하며, 지금까지 사용해온 위치 대신 이름(키워드)을 이용해 함수의 인수를 지정합니다.

키워드 인수에는 두 가지 이점이 있습니다. 첫째, 인수의 위치를 신경 쓰지 않아도 되기 때문에 함수를 사용하기가 쉽습니다. 둘째, 다른 매개변수는 기본 인수 값이 있다는 전제하에 값을 전달하고자 하는 매개변수에만 값을 줄 수 있습니다.

예제(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)

출력 결과:

$ 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)에서는 변수 a에는 인수의 위치에 따라 값 25가 전달됩니다. 그러고 나서 매개변수 c에는 이름, 즉 키워드 인수에 따라 값 24가 전달됩니다. 변수 b에는 기본값인 5가 할당됩니다.

세 번째로 사용하는 func(c=50, a=100)에서는 모든 값에 키워드 인수를 사용합니다. 여기서는 함수를 정의할 때 매개변수 ac 앞에 정의돼 있는데도 함수를 호출할 때는 매개변수 a 앞에서 매개변수 c의 값을 지정하고 있다는 데 유의합니다.

가변 인수

간혹 매개변수 개수에 구애받지 않는 함수, 즉 인수(argument)의 개수가 가변적인(variable) 함수를 정의하고 싶을 때가 있습니다. 그럴 때는 별표를 이용하면 됩니다(function_varargs.py).

def total(a=5, *numbers, **phonebook):
    print('a', a)

    # 튜플의 모든 항목을 순회합니다
    for single_item in numbers:
        print('single_item', single_item)

    # 딕셔너리의 모든 항목을 순회합니다
    for first_part, second_part in phonebook.items():
        print(first_part,second_part)

total(10,1,2,3,Jack=1123,John=2231,Inge=1560)

출력 결과:

$ python function_varargs.py
a 10
single_item 1
single_item 2
single_item 3
Inge 1560
John 2231
Jack 1123

동작 원리

*param처럼 매개변수에 별표를 지정해서 선언하면 그 지점부터 매개변수 목록 끝까지 모든 위치 기준 인수는 'param'이라는 튜플(tuple)에 들어갑니다.

이와 비슷하게 **param처럼 별표를 두 개 지정한 매개변수를 선언하면 그 지점부터 매개변수 목록 끝까지 모든 키워드 인수는 'param'이라는 딕셔너리(dictionary)에 들어갑니다.

튜플과 딕셔너리에 대해서는 이후 장에서 살펴보겠습니다.

return

return 문은 함수에서 돌아오는(return) 데, 즉 함수에서 빠져나오는 데 사용됩니다. 선택사항으로 함수에서 값을 돌려줄(return a value) 수도 있습니다.

예제(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))

출력 결과:

$ python function_return.py
3

동작 원리

maximum 함수는 매개변수 중에서 최댓값을 반환합니다. 이 경우 함수에 숫자가 전달됩니다. 이 함수에서는 간단한 if..else 문으로 큰 값을 찾아서 해당 값을 돌려줍니다.

참고로 값을 지정하지 않은 return 문은 return None과 같습니다. 여기서 None은 파이썬에서 '없음'을 나타내는 특별한 타입입니다. 예를 들어, None은 변수에 None 값이 들어 있더라도 값이 없음을 나타내는 데 사용됩니다.

return 문을 작성하지 않으면 모든 함수는 암묵적으로 return None 문을 맨 끝에 담게 됩니다. 다음과 같이 return 문을 사용하지 않는 some_function 함수가 있을 때 print(some_function())을 실행해 이를 확인할 수 있습니다.

def some_function():
    pass

pass 문은 파이썬에서 문장 블록이 비어있음을 나타내는 데 사용됩니다.

팁: 파이썬에는 이미 '최댓값을 찾는' 기능을 구현한 max라는 함수가 내장돼 있으므로 가급적 이 내장 함수를 사용하세요.

독스트링

파이썬에는 문서 문자열(document string), 보통 줄여서 독스트링(docstring)이라고 하는 훌륭한 기능이 있습니다. 독스트링은 프로그램의 문서화를 개선하고 프로그램을 이해하기 쉽게 만들어주기 때문에 반드시 활용해야 할 중요한 도구입니다. 한 가지 놀라운 점은 프로그램이 실행되는 중에도 함수 같은 것에 지정한 독스트링을 꺼내볼 수도 있다는 것입니다.

예제(function_docstring.py):

def print_max(x, y):
    '''두 숫자 중 최댓값을 출력합니다.

    두 숫자는 정수여야 합니다.'''
    # 가능할 경우 정수로 변환
    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__)

출력 결과:

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

    The two values must be integers.

동작 원리

함수의 첫 번째 논리 라인에 있는 문자열이 해당 함수의 독스트링입니다. 참고로 독스트링은 앞으로 나올 각 장에서 배우겠지만 모듈클래스에도 적용됩니다.

독스트링을 작성할 때는 첫 줄을 대문자로 시작해서 마침표로 끝나는, 여러 줄에 걸친 문자열로 작성하는 것이 관례입니다. 그런 다음 두 번째 줄은 비운 다음 세 번째 줄부터 자세한 설명을 적습니다. 아주 간단한 함수가 아닌 이상 독스트링을 작성할 때는 이러한 관례에 따르기를 적극 권장합니다.

함수의 __doc__(밑줄이 두 개라는 점에 주의합니다) 속성(무언가에 속하는 이름)을 이용해 print_max 함수의 독스트링에 접근할 수 있습니다. 파이썬에서는 모든 것을 객체로 취급하며, 이는 함수도 마찬가지입니다. 객체에 관해서는 클래스를 다룬 장에서 자세히 배우겠습니다.

파이썬에서 help()를 사용해본 적이 있다면 이미 독스트링을 본 것이나 마찬가지입니다! help()가 하는 일은 그저 함수의 __doc__ 속성을 가져와 깔끔하게 표시한 것에 불과합니다. 앞에서 보여드린 함수에 대해서도 이를 시험해 볼 수 있는데, 프로그램에서 help(print_max)를 호출하기만 하면 됩니다. 참고로 help에서 빠져나가려면 q 키를 누릅니다.

자동화된 도구는 이 같은 방법으로 프로그램에서 문서화된 내용을 조회할 수 있습니다. 그러므로 앞으로 작성할 모든 중요한 함수에 대해서는 독스트링을 사용하길 적극 권장합니다. 파이썬 배포판에 포함된 pydoc 명령은 독스트링을 이용해 help()와 비슷한 방식으로 동작합니다.

정리

지금까지 함수의 다양한 측면을 살펴봤지만 그럼에도 모든 측면을 다루지는 못했습니다. 하지만 파이썬 함수와 관련해서 일상적으로 사용하게 될 대부분의 측면들은 다뤘습니다.

다음 장에서는 파이썬 모듈을 사용하는 법을 알아보겠습니다.