|

파이썬 zip 함수란 무엇인가: 여러 리스트를 함께 묶을 때 왜 이렇게 많이 쓸까

파이썬 zip 함수 사용법을 설명하는 대표 이미지
여러 iterable을 나란히 묶어 읽을 때 가장 자주 떠오르는 기본 도구다

파이썬 zip 함수는 아주 자주 보이지만 처음에는 묘하게 낯설 수 있습니다. 리스트 두 개를 넣었더니 튜플이 나오고, 반복문에서는 또 자연스럽게 두 변수로 풀리기 때문입니다. 하지만 핵심은 단순합니다. zip은 여러 iterable의 같은 위치 값을 함께 읽게 해주는 도구입니다.

이번 글에서는 zip이 무엇인지, 왜 병렬 순회에서 편한지, 길이가 다를 때 어떤 일이 생기는지, 그리고 strict=True, zip_longest(), unzip 패턴까지 예시 중심으로 정리하겠습니다.


파이썬 zip 함수 한눈에 보기

파이썬 zip 함수 요약 카드
핵심 카드: iterator, shortest stop, strict, zip_longest
  • zip은 여러 iterable의 같은 위치 값을 튜플로 묶는 iterator다
  • 기본 zip은 가장 짧은 iterable이 끝나면 멈춘다
  • 길이가 반드시 같아야 하면 strict=True를 검토할 수 있다
  • 끝까지 맞춰 보고 싶으면 itertools.zip_longest()가 더 잘 맞는다

zip은 무엇을 하는 함수일까

names = ["Alice", "Bob", "Charlie"]
scores = [90, 80, 95]

paired = zip(names, scores)
print(paired)
print(list(paired))

zip은 0번끼리, 1번끼리, 2번끼리 값을 묶습니다. 그래서 결과는 ("Alice", 90), ("Bob", 80) 같은 튜플 묶음이 됩니다. Python 공식 문서도 zip을 여러 iterable의 항목을 모아 tuples의 iterator를 만드는 built-in으로 설명합니다.


왜 iterator라는 점이 중요할까

names = ["Alice", "Bob"]
scores = [90, 80]

pairs = zip(names, scores)
print(list(pairs))
print(list(pairs))

zip은 바로 리스트를 만드는 것이 아니라 필요할 때 꺼내 쓰는 iterator를 만듭니다. 그래서 한 번 다 소비하고 나면 다시 비게 됩니다. 디버깅할 때 list(pairs)를 한 번 찍은 뒤 두 번째가 비어서 놀라는 이유가 여기 있습니다.


for문에서 zip이 왜 그렇게 자주 보일까

names = ["Alice", "Bob", "Charlie"]
scores = [90, 80, 95]

for name, score in zip(names, scores):
    print(name, score)

이 코드는 이름 목록과 점수 목록을 같은 위치 기준으로 같이 돈다는 의도가 바로 드러납니다. 인덱스를 직접 꺼내서 names[i], scores[i]를 반복하지 않아도 됩니다.

인덱스가 목적이 아니라 같은 위치의 값을 함께 읽는 것이 목적이라면 zip이 더 자연스럽습니다.


enumerate와 함께 쓰는 패턴

names = ["Alice", "Bob", "Charlie"]
scores = [90, 80, 95]

for no, (name, score) in enumerate(zip(names, scores), start=1):
    print(no, name, score)

순번까지 같이 필요하면 이 패턴이 꽤 편합니다. 표 출력, 메뉴 번호, 간단한 리포트 같은 장면에서 자주 씁니다. 관련해서 순번 감각은 파이썬 enumerate는 왜 편할까 글과도 자연스럽게 이어집니다.


길이가 다르면 어떻게 될까

names = ["Alice", "Bob", "Charlie"]
scores = [90, 80]

print(list(zip(names, scores)))

기본 zip은 가장 짧은 iterable이 끝나면 멈춥니다. 그래서 위 예시에서는 "Charlie"가 조용히 사라집니다. 어떤 때는 편하지만, 길이가 꼭 같아야 하는 데이터에서는 버그를 숨길 수도 있습니다.


strict=True와 zip_longest

names = ["Alice", "Bob", "Charlie"]
scores = [90, 80]

for name, score in zip(names, scores, strict=True):
    print(name, score)

길이가 반드시 같아야 하는 데이터라면 strict=True가 도움이 됩니다. 길이가 다르면 ValueError가 나기 때문에 문제를 조용히 넘기지 않고 바로 드러낼 수 있습니다.

from itertools import zip_longest

names = ["Alice", "Bob", "Charlie"]
scores = [90, 80]

print(list(zip_longest(names, scores, fillvalue=None)))

itertools.zip_longest는 가장 긴 iterable이 끝날 때까지 진행하고, 부족한 자리는 fillvalue로 채웁니다. 그래서 누락값을 보존한 채 끝까지 비교하거나 화면에 나란히 보여줄 때 잘 맞습니다.

파이썬 zip 실전 패턴 카드
반복문, dict 생성, enumerate 조합, 병렬 비교에서 특히 자주 쓰인다

unzip은 왜 zip(*pairs)처럼 생겼을까

pairs = [("Alice", 90), ("Bob", 80), ("Charlie", 95)]

names, scores = zip(*pairs)
print(names)
print(scores)

*pairs는 리스트 안의 각 튜플을 zip의 별도 인자로 풀어 줍니다. 그러면 zip은 다시 같은 위치끼리 묶습니다. 그래서 이름들끼리 한 묶음, 점수들끼리 한 묶음이 되어 unzip처럼 동작합니다.


정리

파이썬 zip 함수는 여러 iterable의 같은 위치 값을 묶어 함께 읽는 도구입니다. 그래서 병렬 순회, 두 목록 비교, 키와 값 묶기, unzip 패턴에서 정말 자주 등장합니다.

꼭 같이 기억해야 할 규칙은 네 가지입니다. zip은 iterator이고, 기본 zip은 가장 짧은 iterable에서 멈추고, 길이가 꼭 같아야 하면 strict=True를 검토하고, 끝까지 맞춰야 하면 zip_longest()를 봅니다.

반복문과 읽기 쉬운 파이썬 코드 감각을 더 보고 싶다면 파이썬 enumerate는 왜 편할까, 파이썬 map과 filter, list comprehension 차이, 파이썬 pass, continue, break 차이, 파이썬 defaultdict 쉽게 이해하기도 같이 읽어보면 좋습니다.

공식 기준은 Python zip 문서itertools.zip_longest 문서를 참고했습니다.

함께보면 좋은 글