함수의 기본 인자에 []를 쓰면 함수가 정의될 때 만든 리스트를, 그 인자를 생략한 호출들이 함께 쓴다. 호출마다 빈 리스트로 시작해야 한다면 기본값을 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에서 출력값을 확인했다.