프로그래밍백엔드 개발자

Python에서 인자 전달 방식에 대한 설명과 Python이 이 메커니즘을 구현하는 방법, 함수 설계 시 이를 구별하는 것이 중요한 이유는 무엇인가요?

Hintsage AI 어시스턴트로 면접 통과

답변.

Python이 함수에 인자를 전달하는 방식에 대한 이해는 데이터의 예기치 않은 변경을 방지하고 코드 설계를 올바르게 하는 데 매우 중요합니다.

문제의 역사

전통적인 프로그래밍 언어인 C나 Java에서는 값에 의한 전달(copy by value) 또는 참조에 의한 전달(copy by reference)를 사용합니다. 그러나 Python은 다른 모델을 가지고 있습니다 — 객체 참조에 의한 호출(call by object reference) (때때로 "공유에 의한 호출(call by sharing)"이라고도 합니다).

문제

많은 개발자들이 Python이 항상 참조로 또는 값으로 인자를 전달한다고 잘못 생각합니다. 이는 변경 가능한 객체가 호출하는 코드에서 예기치 않게 수정되는 상황으로 이어집니다.

해결책

Python에서 함수의 매개변수 값은 함수로 전달되는 객체에 대한 참조입니다. 이는 다음을 의미합니다:

  • 객체가 변경 가능(mutable) (리스트, 딕셔너리, 세트 등)인 경우 - 함수 내에서 수정할 수 있으며, 이는 외부에도 반영됩니다.
  • 객체가 변경 불가능(immutable) (정수, 문자열, 튜플, frozenset)인 경우, 함수 내에서 수정하려고 시도하면 새로운 객체가 생성되며 외부에는 영향을 미치지 않습니다.

예:

# 리스트 - 변경 가능(mutable) def add_item(lst): lst.append(42) my_list = [1, 2, 3] add_item(my_list) print(my_list) # [1, 2, 3, 42] # 정수 - 변경 불가능(immutable) def add_num(x): x = x + 1 num = 10 add_num(num) print(num) # 10

주요 특징들:

  • 변경 가능한 객체는 함수 내에서 수정할 수 있으며, 이러한 수정은 외부에서 보입니다.
  • 변경 불가능한 객체는 함수에 의해 영향을 받지 않으며, 단지 새로운 객체가 생성됩니다.
  • Python은 인자를 자동으로 복사하지 않으며, 변경 가능한 구조도 항상 "참조로" 전달됩니다.

트랩 질문들.

Python에서 항상 인자를 참조로 전달하나요?

아니요, Python은 객체에 대한 참조를 전달하며, 객체가 어떻게 동작하는지는 그것이 변경 가능한지 여부에 따라 다릅니다. 변경 불가능한 객체는 어떤 변경이 있더라도 새로운 객체를 생성합니다.

함수 내에서 변경 가능한 인자를 다시 할당하여 외부 객체에 영향을 미칠 수 있나요?

아니요. 함수 내에서 매개변수에 새 값을 할당하면, 외부 객체는 아무런 변화가 없습니다 — 여러분은 단지 로컬 참조를 변경하는 것입니다.

예:

def reassign_list(lst): lst = [99, 100] my_list = [1, 2, 3] reassign_list(my_list) print(my_list) # [1, 2, 3]

기본값으로 리스트를 받는 함수가 재호출 시 이상하게 작동하는 이유는 무엇인가요?

기본값은 함수 정의 시 한 번만 생성되며, 이를 변경하면(예: 요소 추가) 이후 모든 호출에 대해 변경됩니다.

def add_element(x, cache=[]): cache.append(x) return cache print(add_element(1)) # [1] print(add_element(2)) # [1, 2]

일반적인 오류 및 안티 패턴

  • 기본값으로 변경 가능한 인자를 사용하는 것(마지막 예와 같이).
  • 함수가 전달된 리스트나 딕셔너리를 변경하지 않을 것이라고 기대하지만 실제로 수정합니다.
  • 변경 가능 객체 및 변경 불가능 객체 작업 시 함수의 효과를 혼동합니다.

실제 예시

부정적인 사례

프로그래머는 함수를 호출하여 리스트를 전달하고 원래 리스트가 변경되지 않기를 기대하지만, 함수가 요소를 추가합니다.

장점:

  • 빠른 작업, 데이터 복사가 없음.

단점:

  • 예기치 않은 부작용, 누군가 인자의 수정에 대해 몰라서 큰 코드에서 버그 발생.

긍정적인 사례

프로그래머는 함수 내에서 리스트를 명시적으로 복사하여 원본을 변경하지 않고 무언가를 반환합니다:

def process_data(data): data = data.copy() # 또는 list(data) # 복사본으로 안전하게 작업 data.append('보고서') return data

장점:

  • 원본이 보호되어 원하지 않는 부작용이 없음.

단점:

  • 대형 객체의 경우 복사 시 메모리/시간 소모가 발생할 수 있습니다.