파이썬 함수는 인수를 어떻게 전달할까?
파이썬에서 함수의 인수는 항상 참조(reference)로 전달됩니다. 다시 말해, 함수에 객체를 넘기면 값 자체가 복사되는 것이 아니라 해당 객체를 가리키는 참조가 전달됩니다.
이 사실은 내장 함수인 id()를 사용해 확인할 수 있습니다. id()는 객체가 메모리에 저장된 고유 식별값(주소)을 반환하므로, 실제 인수와 형식 매개변수, 그리고 반환된 객체의 id() 값을 비교하면 서로 같은 객체임을 알 수 있습니다.
예제 코드
아래 예제에서는 리스트를 인수로 받아 요소를 추가한 뒤 반환하는 함수를 살펴봅니다.
def foo(x):
print("함수가 전달받은 인수의 id:", id(x))
x.append("20")
return x
a = ["10"]
print("함수 호출 전 인수의 id:", id(a))
b = foo(a)
print("반환된 객체의 id:", id(b))
print(b)
print(a)실행 결과를 보면, 호출 전 변수 a, 함수 내부 매개변수 x, 그리고 반환된 객체 b의 id() 값이 모두 동일합니다.
함수 호출 전 인수의 id: 1475589299912 함수가 전달받은 인수의 id: 1475589299912 반환된 객체의 id: 1475589299912 ['10', '20'] ['10', '20']
즉, 함수 내부에서 x.append("20")으로 리스트를 수정하면 원본 리스트 a도 함께 변경됩니다. 이는 세 변수 모두 메모리상의 같은 리스트 객체를 가리키고 있기 때문입니다.
가변 객체와 불변 객체의 차이
참조로 전달된다는 특성은 객체가 가변(mutable)인지 불변(immutable)인지에 따라 결과가 달라집니다.
- 가변 객체(리스트, 딕셔너리, 집합 등): 함수 내부에서 객체를 직접 수정하면 원본 객체도 변경됩니다.
- 불변 객체(정수, 문자열, 튜플 등): 함수 내부에서 값을 재할당하면 새로운 객체가 생성되므로, 함수 외부의 원본 값은 영향을 받지 않습니다.
주의할 점
원본 객체가 의도치 않게 변경되는 것을 막으려면, 함수에 전달하기 전에 list.copy() 또는 슬라이싱(a[:])으로 복사본을 만들어 전달하는 것이 안전합니다.
정리하면, 파이썬의 인수 전달 방식은 흔히 말하는 C 언어 스타일의 '값에 의한 호출'도, 포인터 기반의 '참조에 의한 호출'도 아닌, 객체 참조에 의한 호출(call by object reference) 방식이라고 이해하는 것이 가장 정확합니다.