컴퓨터

Python 함수의 기본값의 비밀

고래처럼 2023. 4. 25. 11:30
Everything in Python is an object.

 

파이썬에서 모든 것은 개체(오브젝트, object)다. 파이썬 함수도 예외는 아니다. 예전에 파이썬 코딩을 하다가 이상한 것을 목격했다. 빈 리스트를 기본값으로 가지고 있는 함수의 반환값이 계속 변화하는 것이다!

>>> def func(l=[]):
...   l.append('lol')
...   return l
... 
>>> func()
['lol']
>>> func()
['lol', 'lol']
>>> func()
['lol', 'lol', 'lol']
>>> func()
['lol', 'lol', 'lol', 'lol']

이런 일이 발생하는 것은 파이썬에서 함수는 하나의 개체로써, 기본값들을 속성으로 저장하고 있기 때문이다. 함수의 dunder variables 중 하나인 __defaults__를 확인하면 이 사실을 확인할 수 있다.

>>> func.__defaults__
(['lol', 'lol', 'lol', 'lol'],)
>>> func()
['lol', 'lol', 'lol', 'lol', 'lol']
>>> func.__defaults__
(['lol', 'lol', 'lol', 'lol', 'lol'],)

__defaults__는 튜플마다 기본값을 저장한다. 그런데 하필이면 내가 리스트를 저장하도록 지정한 것이다. 그런데 파이썬에서 리스트는 가변(mutable) 데이터이기 때문에, 호출마다 값이 변화할 수 있다. 파이썬 함수가 마치 클로져(closure)인 것처럼 생각하고 코딩하면 이런 실수를 범할 수 있다.

 

이런 문제는 기본값으로 가변값이 아닌, 불변값을 지정함으로써 해결할 수 있다.

>>> def func(l=None):
...   if l is None:
...     l = []
...   l.append('lol')
...   return l
... 
>>> func()
['lol']
>>> func()
['lol']

 

파이썬 함수가 개체인 것을 이용해서 유용한 일들을 할 수 있지만, 이런 함정에 빠지지 않도록 조심하자.

 

참고자료

Fluent Python: Clear, Concise, and Effective Programming: Ramalho, Luciano: 4708364244547: Amazon.com: Books

satwikkansal/wtfpython: What the f*ck Python? 😱 (github.com)