문제의 역사:
언팩을 위한 * 및 ** 연산자는 오래전부터 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를 전달 (오직 키만 언팩됨).개발자가 입력으로 dict를 받아 * 대신 **로 분석합니다. 예상치 못한 동작이 발생하며, 함수에 값을 전달하는 것이 아니라 키만 전달됩니다.
장점:
코드가 즉시 오류를 발생시키지 않으며 “작동하는 것처럼 보인다”.
단점:
숨겨진 오류와 예상되는 논리와의 불일치.
**kwargs를 통해 매개변수를 정확하게 전달하고 딕셔너리를 신중하게 결합하며 시퀀스를 동적으로 통합할 때 *를 사용하는 것.
장점:
최대의 유연성, 간결한 코드, 리팩토링의 용이함.
단점:
매개변수 및 컬렉션의 수가 많을 경우, 이름 및 순서를 주의 깊게 살펴봐야 오류가 발생할 수 있습니다.