프로그래밍백엔드 개발자

Python에서 zip() 내장 함수는 어떻게 작동하며, 어떤 용도로 사용되고, 서로 다른 길이의 시퀀스를 처리할 때 어떤 미세한 문제가 있나요?

Hintsage AI 어시스턴트로 면접 통과

답변.

질문의 역사

zip() 함수는 Python 2에서 등장했으며 (그때는 리스트를 반환함), Python 3부터는 지연 반복기를 반환합니다. 이 함수는 여러 시퀀스를 요소별로 튜플로 "엮어" 주기 때문에, 병렬 반복 가능한 컬렉션을 처리하는 데 편리하고 효율적입니다.

문제점

종종 여러 리스트(또는 다른 종류의 시퀀스)를 동시에 처리해야 할 때가 있습니다. 예를 들어, 키-값 쌍을 순회하거나 점-쌍의 좌표를 처리하는 경우입니다. 인덱스를 수동으로 동기화하는 것은 오류와 코드의 가독성을 떨어뜨리는 원인이 됩니다, 특히 길이가 다른 컬렉션에서요.

해결책

zip() 함수는 임의의 수의 반복 가능한 객체를 받아들이고, 각 반복 가능한 객체에서 해당 요소들이 포함된 튜플의 반복기를 반환합니다. 길이가 다른 시퀀스의 경우, 결과는 가장 짧은 시퀀스에서 중단됩니다.

코드 예제:

names = ['Alice', 'Bob', 'Charlie'] ages = [24, 27, 30] for name, age in zip(names, ages): print(f'{name}{age}세입니다.')

zip을 *을 사용하여 펼칠 수 있습니다:

pairs = [(1, 'a'), (2, 'b'), (3, 'c')] nums, chars = zip(*pairs) print(nums) # (1, 2, 3) print(chars) # ('a', 'b', 'c')

주요 특징:

  • zip()는 반복기( Python 3에서) 를 반환하며, 리스트는 아닙니다.
  • zip()의 작동은 가장 짧은 반복 가능한 데이터를 기준으로 중단됩니다.
  • 명시적인 인덱스 제어 없이 컬렉션을 병렬로 처리할 수 있습니다.

함정 질문들.

길이가 다른 컬렉션을 zip()에 전달하면 어떻게 되나요?

zip()는 가장 짧은 컬렉션의 끝에 도달하면 중단되며, 긴 컬렉션의 나머지 요소는 무시됩니다.

print(list(zip([1,2,3], ['a','b']))) # [(1, 'a'), (2, 'b')]

더 짧은 시퀀스를 기본값으로 보충하여 튜플을 얻으려면 어떻게 해야 하나요?

표준 zip()은 그렇게 할 수 없지만, 이를 위해 itertools.zip_longest가 있습니다:

from itertools import zip_longest for a, b in zip_longest([1,2], ['x','y','z'], fillvalue=None): print(a, b) # 1 x # 2 y # None z

zip()의 결과를 "언팩"하여 원래 리스트를 다시 얻을 수 있나요?

네, 모든 원본 컬렉션이 같은 길이를 가지며 결과가 변경되지 않았다면, * 연산자를 사용하여 zip을 펼칠 수 있습니다.

pairs = [(1,2), (3,4)] a, b = zip(*pairs) print(a) # (1, 3) print(b) # (2, 4)

일반적인 오류 및 반패턴

  • zip()가 항상 가장 긴 컬렉션의 끝까지 "도달할" 것이라고 기대하세요.
  • Python 3에서 zip()가 리스트를 반환한다고 가정하세요 (이것은 반복기로 때로는 list()로 감싸야 함).
  • 변경 가능한 소스에서 zip을 사용하여 각 반복에서 소비되는 코드를 사용하세요.

실생활의 예

부정적인 케이스

길이가 다른 관련 컬렉션을 zip의 특성을 고려하지 않고 처리:

lst1 = [1,2,3,4] lst2 = ['a','b'] for x, y in zip(lst1, lst2): print(x, y) # 1 a # 2 b # (3,4)와 'c', 'd'는 lst1에서 처리되지 않았습니다.

장점:

  • 시퀀스가 보장되게 동일한 길이인 경우 간단하고 직관적입니다.

단점:

  • 컬렉션의 실제 길이가 다를 경우 값이 손실됩니다.

긍정적인 케이스

fillvalue를 사용하여 zip_longest로 모든 요소를 보존:

from itertools import zip_longest lst1 = [1,2,3,4] lst2 = ['a','b'] for x, y in zip_longest(lst1, lst2, fillvalue='?'): print(x, y) # 1 a # 2 b # 3 ? # 4 ?

장점:

  • 모든 요소의 처리가 보장됩니다.
  • "빈" 값을 명시적으로 지정할 수 있습니다.

단점:

  • 외부 모듈을 임포트해야 합니다.
  • fillvalue를 잊지 않는 것이 중요합니다, 그렇지 않으면 기본값으로 None이 됩니다.