CS Repository/기초 강화학습

python 애스터리스크(*) - 언패킹의 역할과 예제

조금씩 차근차근 2025. 8. 25. 11:41

파이썬에는 애스터리스크가 포인터도 아닌 것이 특이한 일을 하고 있어, 이 코드를 처음 보면 당황하기 부지기수이다.

파이썬의 애스터리스크 기호의 사용법에 대해 자세히 알아보자.

  • 대입 언패킹
  • 함수 호출 시 언패킹
  • 리터럴 내부 언패킹

대입 언패킹 (Extended Iterable Unpacking, PEP 3132)

  • 오른쪽 이터러블을 왼쪽 변수들에 “펼쳐” 넣는다.
  • *가 붙은 변수는 나머지 전부리스트로 받는다.
    • *각 패턴 레벨에서 최대 1개만 허용된다.
a, *rest = [10, 20, 30]
*head, b = (1, 2, 3, 4)
x, *mid, y = range(5)  

 

  • * 변수는 항상 리스트가 된다.(튜플 아님).
  • 최소 길이만 맞으면 남는 요소가 0개여도 동작한다(그 경우 빈 리스트 ([])가 됨).
a, *rest = [42]

 

 

튜플 내 애스터리스크가 존재할 경우, 가장 가까운 튜플을 기준으로 애스터리스크 작업을 수행한다.

(a, *b), c = ([1, 2, 3], 9)

흔한 패턴

first, *_, last = some_list   # 중간은 버리고 양끝만
*lines, _ = open("file.txt")  # 마지막 한 줄만 버리기
a, *b = [1, 2, 3]  # 남는 데이터 흡수

함수 호출 시 언패킹

  • *iterable → 위치 인자들로 펼침
  • **mapping → 딕셔너리 내 원소들을 키워드 인자들로 펼침
def f(x, y, z, sep="-"):
    print(x, y, z, sep=sep)

args = (1, 2, 3)
kw   = {"sep": " / "}
f(*args, **kw)

![[Pasted image 20250825112903.png]]

여러 번 섞어서도 가능하다.

print(*(1, 2), *[3, 4], 5, **{"end": "\n"})

 

주의사항

  • 중복 키는 에러
def g(x):
    pass
# g(x=1, **{"x": 2})

 

  • *에 건네는 것은 이터러블이어야 함(정수 불가).
  • 이터레이터(제너레이터 등)를 *로 펼치면 한 번에 전부 소모된다.
    • 커서가 이동한다.

리터럴 내부 언패킹 (PEP 448)

리스트/튜플/세트/딕셔너리 리터럴 안에서 합치기/펼치기가 된다.

a = [1, 2]; b = [3, 4]
[*a, 99, *b]

 

t = (0, *range(3))

 

s = {*{1, 2}, *{2, 3}}

 

값이 겹칠 경우

d1 = {"x": 1, "y": 2}
d2 = {"y": 999, "z": 3}
print({**d1, **d2})

 

  • y값에 주목하자.
  • 뒤의 키가 우선된다.

자주 쓰는 실전 패턴

로그/문자열 파싱

line = "2025-08-25 INFO server started 8080"
date, level, *msg_parts = line.split()
msg = " ".join(msg_parts)  # 'server started 8080'

루프에서 헤드/테일 나누기

rows = [(1,2,3),(4,5,6)]
for a, *rest in rows:
    # a는 첫 컬럼, rest는 나머지
    ...

슬라이싱 대체(양끝만 필요할 때)

first, *_, last = seq

안전한 “나머지 무시”

val, *_ = expensive_iterable()  # 첫 값만 쓰고 나머지는 버림

성능 & 메모리 팁

  • [*iterable]list(iterable)과 동일하게 새 리스트를 만든다. 큰 이터러블이면 메모리 사용량을 고려하고 사용하자.
  • 큰 리스트들을 합칠 때
    • 새 리스트가 필요하면: [*a, *b, *c]
    • 가능한 한 제너레이터로 흘리는 게 메모리 효율적이다.
      from itertools import chain
      for x in chain(a, b, c):
      ...
  • sum(list_of_lists, [])로 리스트 합치기는 지양(O(n²) 위험). 언패킹이나 itertools.chain 사용하기.

흔한 함정 요약

  • 대입 언패킹에 *한 레벨당 1개만 사용해야 한다.
  • *var는 항상 list 타입이다.
  • 호출 시 *는 이터러블만, **는 매핑만.
  • 이터레이터는 *로 펼치면 즉시 전량 소비된다.
  • 딕셔너리 언패킹은 뒤에 오는 것이 덮어쓴다.
    • 딕셔너리 병합에서 키 충돌은 뒤쪽이 덮어씀을 명확히 의도하고 사용해야 한다.