[Python] 기본 인자에 빈 리스트를 쓰면 값이 남는 이유

차곡코딩·약 16시간 전

Python · 기초 문법

목록 보기
7/7

함수에 리스트를 전달하지 않으면 빈 리스트부터 시작하도록 만들고 싶을 때가 있습니다. items=[]라고 작성하면 자연스러워 보이지만, 호출할 때마다 새 리스트가 만들어지는 것은 아닙니다.

두 번째 호출에 첫 번째 값이 남습니다

def add_topic(topic, topics=[]):
    topics.append(topic)
    return topics

print(add_topic("Python"))
print(add_topic("SQL"))
['Python']
['Python', 'SQL']

기본 인자는 함수가 정의될 때 평가됩니다. 위 함수는 정의 시 만들어진 리스트를 기본값으로 보관하고, 인자를 생략한 호출에서 그 객체를 다시 사용합니다. append()가 리스트 자체를 변경하므로 다음 호출에도 이전 값이 남습니다.

이 현상은 리스트만의 문제가 아닙니다. 딕셔너리나 집합처럼 변경 가능한 객체를 기본값으로 두고 수정할 때도 주의해야 합니다.

호출마다 새 리스트가 필요하면 함수 안에서 만듭니다

def add_topic(topic, topics=None):
    if topics is None:
        topics = []
    topics.append(topic)
    return topics

first = add_topic("Python")
second = add_topic("SQL")

assert first == ["Python"]
assert second == ["SQL"]
assert first is not second

여기서는 None을 “리스트를 전달하지 않았다”는 표시로 사용합니다. 실제 빈 리스트 생성은 함수가 실행될 때 이루어지므로 두 호출의 결과가 서로 다른 객체입니다.

if not topics로 바꾸면 빈 리스트를 직접 전달한 경우까지 새 리스트로 교체합니다. None과 빈 리스트의 의미를 구분하려면 is None으로 확인하는 것이 정확합니다.

전달받은 리스트는 여전히 바뀝니다

original = ["Git"]
result = add_topic("Python", original)

assert original == ["Git", "Python"]
assert result is original

기본값 문제를 해결했다고 해서 원본 보존까지 보장되는 것은 아닙니다. 이 함수는 전달받은 리스트에 항목을 추가하도록 작성되어 있습니다.

원본을 변경하지 않는 함수가 필요하다면 별도의 리스트를 만들어 반환할 수 있습니다.

def with_topic(topic, topics=None):
    result = [] if topics is None else list(topics)
    result.append(topic)
    return result

original = ["Git"]
assert with_topic("Python", original) == ["Git", "Python"]
assert original == ["Git"]

list(topics)는 얕은 복사입니다. 중첩된 객체까지 복제하지는 않지만, 이 예제처럼 문자열 항목을 새 리스트에 추가하는 용도에는 충분합니다.

함수를 검토할 때는 기본 객체가 언제 만들어지는지와 전달받은 객체를 변경하는지를 별도로 확인하려고 합니다. 두 질문을 나누면 호출 간 값이 섞이는 원인도 더 명확하게 찾을 수 있습니다.

참고: Python 공식 문서 — 기본 인자

profile
비전공자의 개발 성장 기록. 바이브코딩 프리랜서 경험부터 Python·SQL·AI 서비스 개발까지

0개의 댓글