프로그래밍풀스택 파이썬 개발자

Python에서 시퀀스 및 딕셔너리를 언팩할 때 * 및 ** 연산자의 작동 메커니즘을 설명하십시오. 미세한 포인트는 무엇이며, 이것이 유용한 경우는 어디인가요?

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

답변.

문제의 역사:

언팩을 위한 *** 연산자는 오래전부터 Python에 있었지만, 버전이 업데이트될수록 사용이 확장되었습니다 (예: Python 3.5에서 ***를 통해 여러 컬렉션을 결합하는 지원이 추가됨). 이 연산자들은 인수 전달 및 함수 내에서 인수를 수집할 때 컬렉션 작업을 더 유연하게 만듭니다.

문제점:

동적 시퀀스 사용 시, 가변 인수 개수의 매개변수를 전달할 때, 컬렉션의 크기를 수동으로 확인하고 반복문을 작성해야 할 필요가 생깁니다. ***의 용도를 구분하지 못하거나 잘못 사용하면 오류가 쉽게 발생합니다.

해결책:

* 연산자는 시퀀스(list, tuple, set)를 언팩하는데 사용되며, ** 연산자는 함수 호출 시 또는 여러 딕셔너리를 결합할 때 딕셔너리를 언팩하는 데 사용됩니다. 이는 매개변수를 우아하게 전달하고 컬렉션을 합치며, 임의의 구조를 쉽게 함수 매개변수로 변환할 수 있게 해줍니다.

코드 예시:

def foo(a, b, c): print(a, b, c) args = (1, 2, 3) foo(*args) # 1 2 3 params = {'a': 10, 'b': 20, 'c': 30} foo(**params) # 10 20 30 list1 = [1, 2] list2 = [3, 4] combined = [*list1, *list2] print(combined) # [1, 2, 3, 4]

주요 특징:

  • *sequence는 개별 위치 인수로 요소를 전달하고, **dict는 이름이 지정된 인수로 전달합니다.
  • [*a, *b]{**d1, **d2}를 통해 우아하게 컬렉션을 합치고 복사할 수 있습니다.
  • 언팩은 함수 정의/선언 시뿐만 아니라 호출 시에도 사용됩니다.

함정이 있는 질문.

**혼합된 컬렉션에 대해 * 및 를 사용할 수 있습니까?

함수 호출 시 *는 위치 인수에 대해서만 작동하고, **는 이름이 지정된 인수에 대해서만 작동합니다. 언팩되지 않은 dict를 *로 전달하거나 시퀀스를 **로 전달하면 오류가 발생합니다.

def foo(a, b): print(a, b) foo(*{'a': 1, 'b': 2}) # 출력: a b (딕셔너리의 키, 값이 아님!)

**{**d1, d2}를 통해 dict를 결합할 때 키명이 중복되면 어떻게 됩니까?

결과적으로 마지막 dict에서 해당 키의 값이 사용됩니다.

d1 = {'x': 1, 'y': 2} d2 = {'y': 33, 'z': 44} merged = {**d1, **d2} print(merged) # {'x': 1, 'y': 33, 'z': 44}

**리스트 표현식이나 딕셔너리 표현식 내에서 * 및 를 사용할 수 있습니까?

네, Python 3.5부터 합법적입니다, 예:

lst = [1, 2, *range(3, 6)] # [1, 2, 3, 4, 5] dct = {**{'a': 1}, 'b': 2, **{'c': 3}}

일반적인 오류 및 안티 패턴

  • *로 dict를 전달 (오직 키만 언팩됨).
  • 이름이 지정된 인수 간의 과도한 충돌로 TypeError 발생.
  • 매핑이 아닌 객체에 대해 **를 사용하려고 시도.

실생활 예시

부정적 케이스

개발자가 입력으로 dict를 받아 * 대신 **로 분석합니다. 예상치 못한 동작이 발생하며, 함수에 값을 전달하는 것이 아니라 키만 전달됩니다.

장점:

코드가 즉시 오류를 발생시키지 않으며 “작동하는 것처럼 보인다”.

단점:

숨겨진 오류와 예상되는 논리와의 불일치.

긍정적 케이스

**kwargs를 통해 매개변수를 정확하게 전달하고 딕셔너리를 신중하게 결합하며 시퀀스를 동적으로 통합할 때 *를 사용하는 것.

장점:

최대의 유연성, 간결한 코드, 리팩토링의 용이함.

단점:

매개변수 및 컬렉션의 수가 많을 경우, 이름 및 순서를 주의 깊게 살펴봐야 오류가 발생할 수 있습니다.