함수

이 노트북은 제이크 반더플라스(Jake VanderPlas)의 A Whirlwind Tour of Python(OReilly Media, 2016)를 기반으로 만들어졌습니다. 이 내용은 CC0 라이센스를 따릅니다. 전체 노트북의 목록은 https://github.com/rickiepark/WhirlwindTourOfPython 에서 볼 수 있습니다.

< 제어문 | 목차 | 에러와 예외처리 >

 

지금까지는 간단하고 일회성 코드 블럭을 만들었습니다. 파이썬 코드를 조직하여 가독성과 재사용성을 높이는 한가지 방법은 유용한 코드 일부를 재사용 가능한 함수로 뽑아내는 것입니다. 여기서는 함수를 만드는 두 가지 방법을 다룹니다. 어떤 종류의 함수도 만들 수 있는 def 문과 짧고 익명의 함수를 만드는 lambda 문입니다.

함수 사용하기

함수는 이름을 가진 코드 묶음이며 소괄를 사용하여 호출됩니다. 이미 함수를 보았습니다. 예르 들어, 파이썬 3에서 print는 함수입니다:

print('abc')
abc

여기에서 print는 함수 이름이고 'abc'는 함수의 매개변수입니다.

매개변수에 이름을 지정할 수 있는 키워드 매개변수도 있습니다. print() 함수에 있는 (파이썬 3에서) 유일한 키워드 매개변수는 sep입니다. 이 매개변수는 여러개의 아이템을 구분할 때 사용할 문자나 문자열을 지정합니다:

print(1, 2, 3)
1 2 3
print(1, 2, 3, sep="--")
1--2--3

일반 매개변수와 키워드 매개변수가 함께 쓰일 때 키워드 매개변수는 맨 뒤에 위치해야 합니다.

함수 정의

여러 곳에서 사용되는 기능을 조직화하여 자신만의 함수를 정의할 때 함수의 가치가 빛을 발합니다. 파이썬에서 함수는 def 문으로 정의합니다. 예를 들어, 이전 섹션에서 피보나치 수열 코드를 다음과 같이 함수로 만들 수 있습니다:

def fibonacci(N):
    L = []
    a, b = 0, 1
    while len(L) < N:
        a, b = b, a + b
        L.append(a)
    return L

이제 매개변수 N 하나를 가지고 무언가를 하는 fibonacci 이름의 함수 하나가 만들어졌습니다. return은 값을 반환합니다. 여기에서는 N 개의 피보나치 수열의 리스트를 반환합니다:

fibonacci(10)
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

C와 같은 고정 타입의 언어에 익숙하다면 함수의 입력과 출력에 연관된 타입 정보가 없다는 것을 눈치챘을 것입니다. 파이썬의 함수는 간단하거나 복합적인 어떤 파이썬 오브젝트도 반환할 수 있습니다. 다른 언어에서는 어려울 수 있는 작업이 파이썬에서는 간단합니다.

예를 들면, 콤마로 구분하여 여러 값을 반환하면 하나의 튜플로 연결됩니다:

def real_imag_conj(val):
    return val.real, val.imag, val.conjugate()

r, i, c = real_imag_conj(3 + 4j)
print(r, i, c)
3.0 4.0 (3-4j)

매개변수 기본값

종종 함수를 정의할 때 주로 사용했으면 하는 어떤 값이 있습니다. 또 사용자가 바꿀 수도 있어야 합니다. 이런 경우에 매개변수에 기본값을 지정할 수 있습니다. 이전의 fibonacci 함수를 생각해 보죠. 사용자에게 시작 값을 정할 수 있게 하면 어떨까요? 다음과 같이 만들 수 있습니다:

def fibonacci(N, a=0, b=1):
    L = []
    while len(L) < N:
        a, b = b, a + b
        L.append(a)
return L

하나의 매개변수만 사용하면 함수의 결과는 이전과 동일합니다:

fibonacci(10)
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

하지만 시작값 등을 바꾸어 사용할 수 있습니다:

fibonacci(10, 0, 2)
[2, 2, 4, 6, 10, 16, 26, 42, 68, 110]

키워드 매개변수 순서가 다를 경우 이름과 함께 값을 지정할 수 있습니다:

fibonacci(10, b=3, a=1)
[3, 4, 7, 11, 18, 29, 47, 76, 123, 199]

*args와 **kwargs: 유연한 매개변수

이따금 사용자가 얼마나 많은 매개변수를 전달할지 알 수 없는 함수를 만들어야 할 때가 있습니다. 이런 경우에 전달되는 모든 매개변수를 담을 수 있는 특별한 형태인 *args**kwargs를 사용할 수 있습니다. 다음 예를 보겠습니다:

def catch_all(*args, **kwargs):
    print("args =", args)
    print("kwargs = ", kwargs)
catch_all(1, 2, 3, a=4, b=5)
args = (1, 2, 3)
kwargs = {'a': 4, 'b': 5}
catch_all('a', keyword=2)
args = ('a',)
kwargs = {'keyword': 2}

argskwargs 이름이 중요한 것이 아니라 앞에 붙은 * 문자가 중요합니다. argskwargs는 관례적으로 자주 사용하는 이름으로 “arguments”와 “keyword arguments”의 약자입니다. 작동 방식은 * 문자로 결정됩니다. 변수 앞에 하나의 *가 있으면 시퀀스로 확장하라는 뜻이고, 변수 앞에 두 개의 *가 있으면 딕셔너리로 확장하라는 뜻입니다. 사실 이 문법은 함수 정의 뿐만 아니라 함수 호출에서도 사용할 수 있습니다!

inputs = (1, 2, 3)
keywords = {'pi': 3.14}
catch_all(*inputs, **keywords)
args = (1, 2, 3)
kwargs = {'pi': 3.14}
print(inputs)
(1, 2, 3)
print(*inputs)
1 2 3

익명 (lambda) 함수

앞에서 함수를 정의하는 가장 일반적인 방법인 def 문을 다루었습니다. 다른 방법으로 짧고 일회성 함수를 정의하는 lambda 문이 있습니다. 다음과 같습니다:

add = lambda x, y: x + y
add(1, 2)
3

이 람다 함수는 다음과 거의 동일합니다.

def add(x, y):
    return x + y

왜 이런 함수가 필요한 걸까요? 기본적으로 파이썬에서 모든 것이 객체이기 때문에 발생합니다. 심지어 함수도 객체입니다! 이 말은 함수의 매개변수로 함수를 전달할 수 있다는 뜻입니다.

예제를 위해서 딕셔너리의 리스트를 만들어 보겠습니다:

data = [{'first':'Guido', 'last':'Van Rossum', 'YOB':1956},
        {'first':'Grace', 'last':'Hopper', 'YOB':1906},
        {'first':'Alan', 'last':'Turing', 'YOB':1912}]

이제 이 데이터를 정렬해보겠습니다. 파이썬은 sorted 함수를 제공합니다:

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

하지만 딕셔너리는 순서가 없습니다. 어떻게 데이터를 정렬할지 알려 주어야 합니다. key 매개변수에 아이템을 정렬할 키를 반환해 주는 함수를 지정하여 해결할 수 있습니다:

# 'first'를 기준으로 알파벳 순으로 정렬합니다
sorted(data, key=lambda item: item['first'])<code></code>
[{'first': 'Alan', 'last': 'Turing', 'YOB': 1912},
{'first': 'Grace', 'last': 'Hopper', 'YOB': 1906},
{'first': 'Guido', 'last': 'Van Rossum', 'YOB': 1956}]
# 생년을 기준으로 정렬합니다
sorted(data, key=lambda item: item['YOB'])
[{'first': 'Grace', 'last': 'Hopper', 'YOB': 1906},
{'first': 'Alan', 'last': 'Turing', 'YOB': 1912},
{'first': 'Guido', 'last': 'Van Rossum', 'YOB': 1956}]

이런 키 함수를 보통의 def 문으로 생성하여 사용할 수 있지만 lambda 문을 사용해 일회용 함수를 사용하는게 편리합니다.

 

< 제어문 | 목차 | 에러와 예외처리 >

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

%s에 연결하는 중

This site uses Akismet to reduce spam. Learn how your comment data is processed.