파이썬 함수의 기본 리스트에 이전 값이 남는 이유

이 카테고리 글 목록

전체글 보기

함수의 기본 인자에 []를 쓰면 함수가 정의될 때 만든 리스트를, 그 인자를 생략한 호출들이 함께 쓴다. 호출마다 빈 리스트로 시작해야 한다면 기본값을 None으로 두고 함수 안에서 리스트를 만든다.

첫 번째 결과에 두 번째 값이 붙는 이유

호출마다 작업 이름 하나를 담은 목록을 받으려는 가상 예다. 첫 번째 결과를 따로 보관한 뒤 함수를 다시 부른다.

def collect(name, names=[]):
    names.append(name)
    return names

first = collect("초안")
print(first)
second = collect("검토")
print(first)
print(first is second)
['초안']
['초안', '검토']
True

첫 출력에는 초안만 있다. 두 번째 호출의 append가 같은 리스트에 검토를 붙이므로, 보관해 둔 first에서도 변경이 보인다. is의 True는 두 변수가 같은 객체를 가리킨다는 뜻이다. Python의 기본 인자 설명에서 이 평가 시점을 확인할 수 있다.

인자를 생략했을 때 새 목록 만들기

def collect(name, names=None):
    if names is None:
        names = []
    names.append(name)
    return names

first = collect("초안")
second = collect("검토")
print(first, second)
print(first is second)

provided = []
result = collect("보관", provided)
print(provided)
print(result is provided)
['초안'] ['검토']
False
['보관']
True

names is None은 생략했거나 명시적으로 None을 넘겼을 때 참이다. if not names를 쓰면 호출자가 넘긴 빈 리스트도 새 객체로 바꾼다. 이 함수는 전달받은 리스트에 값을 추가하도록 정했으므로, provided가 비어 있어도 그 리스트를 쓴다.

호출자가 준 목록까지 보존하려면, 전달받은 경우에도 새 바깥 리스트를 만든 뒤 그쪽에 추가한다. list(names)로 복사하면 기존 요소의 참조는 유지되므로 중첩 값도 바꾸는 함수라면 그 범위를 따로 정해야 한다. 얕은 복사에서 중첩 변경이 전해지는 이유가 그 다음 문제다.

각 코드 블록은 따로 실행할 수 있다. CPython 3.14.3과 Windows 11에서 출력값을 확인했다.

이 카테고리의 다른 글

전체글 보기

댓글 남기기