[BW 8] 여러 이터레이터에 대해 나란히 루프를 수행하려면 zip을 사용하라

문제 : 가장 긴 이름을 가진 동물을 찾아라.

초기 세팅 코드

longest_name = None
maxi = 0

animals = ['outer', 'hamster', 'dog']
counts = [len(n) for n in animals]

배열 인덱스 i를 사용한 코드

# 인덱스 i를 두 번 참조하여 시각적으로 잡음이 많다.
for i in range(len(animals)):
    count = counts[i]
    if maxi < count:
        longest_name = animals[i]
        maxi = count

print(longest_name)

>>>
hamster

zip을 사용한 코드

for name, count in zip(animals, counts):
    if count > maxi:
        longest_name = name
        maxi = count

print(longest_name)

>>>
hamster
  • zip은 둘 이상의 이터레이터를 지연 계산 제네레이터를 사용해 묶어준다.
  • zip은 자신이 감싼 이터레이터 원소를 하나씩 소비한다.
  • 따라서 메모리를 다 소모해서 프로그램이 중단되는 위험 없이 아주 긴 입력도 처리할 수 있다.

이터레이터의 길이가 서로 다를 때

# 원래대로라면 elephant가 나와야 하는데 hamster가 나온다.
## 그 이유는 elephant의 길이 리스트를 갱신하지 않았기 때문이다.
animals.append('elephant')

for name, count in zip(animals, counts):
    if count > maxi:
        longest_name = name
        maxi = count

print(longest_name)

>>>
hamster
  • zip은 자신이 감싼 이터레이터 중 어느 하나가 끝날 때까지 튜플을 반환한다.
  • 따라서 출력은 가장 짧은 입력 이터레이터의 길이와 같다.

길이가 다르더라도 모두 조회해야 할 때

import itertools

for name, count in itertools.zip_longest(animals, counts, fillvalue=None):
    print(f'{name}: {count}')
    
>>>
outer: 5
hamster: 7
dog: 3
elephant: None
  • fillvalue 파라미터의 디폴트 값은 None 이지, 원하는 값을 지정할 수 있다.