function의 default parameter 사용 시 주의점

파이썬은 함수를 정의할 때 default parameter(기본값)을 같이 정의할 수 있다.
편리한 기능이지만 아래와 같이 list나 dictionary와 같은 object를 사용할 경우 버그가 날 확률이 높다.
(물론 의도적이라면 예외이다.)

1
2
3
4
5
6
7
8
9
def list_func(li=[]):
li.append('test')
print('li:', li)
print('#############')

list_func() # li: ['test']
list_func() # li: ['test', 'test']
list_func() # li: ['test', 'test', 'test']
list_func() # li: ['test', 'test', 'test', 'test']

아무 parameter도 전달하지 않았을 경우 default parameter가 빈 list이기 때문에 함수내에서 li를 print하면 당연히 ‘“test” 하나 들어간 list가 출력되겠지’라고 생각하겠지만
막상 실행 시켜보면 주석을 달아놓은 것과 같이 list_func()를 실행할 때 마다 ‘test’가 하나 씩 추가된다.
이는 함수를 정의할 때 default parameter로 지정한 object도 같이 생성되고 이를 default parameter로 계속 사용하기 때문이다.

파이썬 docs에서도 해당 사실에 대해 자세히 써놓았다.
https://docs.python.org/3.7/reference/compound_stmts.html#function-definitions

Default parameter values are evaluated from left to right when the function definition is executed. This means that the expression is evaluated once, when the function is defined, and that the same “pre-computed” value is used for each call. This is especially important to understand when a default parameter is a mutable object, such as a list or a dictionary.

id() 함수를 통해 identity를 찍어보면 항상 같은 identity가 나오는 걸 확인할 수 있다.

1
2
3
4
5
6
7
8
9
10
def list_func(li=[]):
li.append('test')
print('li:', li)
print(id(li))
print('#############')

list_func()
list_func()
list_func()
list_func()

그러면 아무 파라미터도 전달하지 않으면 빈 리스트를 전달한 것 처럼 하려면 어떻게 해야할까?
물론 답은 여러가지지만 나는 아래와 같이 default parameter를 None으로 한 다음 아래와 같이 로직을 짰다.

1
2
3
4
5
6
7
8
9
10
def list_func(li=None):
li = [] if li is None else li
li.append('test')
print('li:', li)
print('#############')

list_func()
list_func()
list_func()
list_func()
Share