Effective Python C1. Pythonic(8) - zip의 사용
Introduction
파이썬에서 객체가 들어있는 리스트를 다수 다루는 경우가 많으며, 리스트 컴프리헨션을 사용하면 소스 list에서 새로운 list를 파생시키기 쉽다.
Best WAY 8 : 여러 이터레이터에 대해 나란히 루프를 수행하려면 zip을 사용하라.
두 리스트에서 원소를 동시에 가져오려는 경우, 인덱스를 쓸 필요없이 zip으로 동시에 가져올 수 있다. 아래 예제는 counts의 값이 가장 큰 name을 구하는 로직이다.
# 시각적 잡음이 않은 이터레이션.
longest_name = None
max_count = 0
for i in range(len(names)):
count = counts[i]
if count > max_count:
longest_name = names[i]
max_count = count
# enumerate를 썼으나, 아직 부족한 느낌.
for i, name in enumerate(names):
count = counts[i]
if count > max_count:
longest_name = name
max_count = count
# zip을 사용해 좀 더 깔끔하게 코드를 작성
for name, count in zip(names, counts):
if count > max_count:
longest_name = name
max_count = count
zip은 자신이 감싼 이터레이터 원소를 하나씩 꺼낸다. 따라서 메모리를 다 소모해서 프로그램이 중단되는 위험도 없이 매우 긴 입력도 처리 가능하다 .
주의할 것은 zip이 감싼 이터레이터 원소의 길이가 각각 다를 때이다. 이 경우 출력이 가장 짧은 이터레이터 원소가 출력 길이의 기준이 된다.
name.append('LEE')
for name, count in zip(names, counts):
print(name)
>>>
Cecilia
남궁민수
이를 방지하려면 길이가 긴 원소에 맞춰 출력 길이가 정해지는 zip_longest를 사용할 수 있다. 이때 길이가 짧은 원소의 경우 출력 길이를 넘어가면 None으로 채워진다. 단, 이 값은 fillvalue로 수정 가능하다.
import itertools
for name, count in itertools.zip_longest(names, counts):
print(f"{name} : {count}")
>>>
Cecilia: 7
남궁민수: 4
LEE : None
Discussion
- zip 함수로 나란히 여러 이터레이터를 이터레이션할 수 있다는 장점을 잘 살려서 코딩하자.
Summary
- zip 내장 함수로 여러 이터레이터를 나란히 이터레이션할 수 있다.
- zip은 튜플을 지연 계산하는 제너레이터를 만든다.
Reference
파이썬 코딩의 기술 제 2판. - 브렛 슬리킨 지음 / 오현석 옮김