Python 함수 기본 인자에 리스트를 썼다가 데이터가 계속 쌓인 이유
문제 발생
기본 인자를 빈 리스트로 준 함수를 여러 번 호출했더니, 이전 호출에서 추가한 값이 다음 호출에도 남아있는 버그가 발생했습니다.
def add_item(item, items=[]):
items.append(item)
return items
print(add_item("a")) # ['a']
print(add_item("b")) # ['a', 'b'] -- 기대와 다름, 새 리스트가 아님원인 분석
Python은 함수의 기본 인자값을 함수가 정의되는 시점에 딱 한 번만 평가합니다. 매 호출마다 새로 만드는 것이 아닙니다. items=[]의 []는 함수가 정의될 때 생성된 하나의 리스트 객체이고, 이 객체가 모든 호출에서 공유됩니다. 리스트, 딕셔너리, 셋처럼 가변(mutable) 객체를 기본값으로 쓰면 한 호출에서 수정한 내용이 다음 호출에도 그대로 남습니다.
반대로 정수, 문자열, 튜플처럼 불변(immutable) 객체를 기본값으로 쓰면 애초에 내부에서 수정할 방법이 없으므로 이 문제가 발생하지 않습니다.
해결 방안
기본값을 None으로 주고, 함수 본문에서 실제 기본값을 새로 만듭니다.
def add_item(item, items=None):
if items is None:
items = []
items.append(item)
return items
print(add_item("a")) # ['a']
print(add_item("b")) # ['b'] -- 매번 새 리스트이 패턴은 딕셔너리, 셋 등 다른 가변 기본값에도 동일하게 적용합니다. 반대로 이 동작을 의도적으로 활용하는 경우도 있습니다 — 함수 호출 사이에 상태를 캐싱하고 싶을 때 가변 기본 인자를 캐시 저장소로 쓰는 기법인데, 의도가 명확히 드러나도록 주석을 남기지 않으면 다음에 코드를 보는 사람이 버그로 오해하기 쉽습니다.
공식 문서
- Python Docs: Default Argument Values — "the default value is evaluated only once"라고 명시되어 있습니다.
댓글0
댓글을 남기려면 로그인이 필요해요. 로그인
아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.