리스트 컴프르헨션을 사용하면 소스 list에서 새로운 list를 파생되기 쉽다
names = [ ' Cecilia ' , ' 남궁만수' , ' abc' ]
counts = [len(n) for n in names]
print(count) #[7,4,3]
두 리스트를동시에 이터레이션할 경우 names 소스 리스트의 길이를 사용해서 이터레이션할 수 있다.(with 인덱싱)
시각적 잡음이 많다.
인덱스를 사용해 names와 counts의 원소를 찾는 과정을 어렵게 한다.
배열 인덱스 i를 사용하여 배열 원소를 가져오는 연산이 두 번 일어난다.
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
print(longest_name) #Cecilia
range보단 enumerate사용하라(batter way07)
for i, name in enumerate(names):
count = counts[i]
if count > max_count:
longest_name = name
max_count = count
둘 이상의 이터레이터를 지연 계산 제너레이터를 사용하여 묶음
zip 제너레이터는 각 이터레이터의 다음 값이 들어 있는 튜플을 반환한다.
이 튜플을 for 문에서 바로 언패킹할 수 있다.
인덱싱을 사용하는 것보다 깔끔하다.
자신이 감싼 이테레이터 원소를 하나씩 소비하기에 메모리를 다 소모해서 프로그램이 중단되는 위험 없이 아주 긴 입력 처리 가능하다.
for name, count in zip(names, counts):
if count > max_count:
longest_name = name
max_count = count
zip는 다른 원소를 추가해도 출력이 되지 않는다.
- zip는 자신이 감싼 이터레이터 중 어느 하나가 끝날 때까지 튜플을 내놓은다.
- 출력은 가장 짧은 입력의 길이와 같다.
names.append('Rosalind')
for name, count in zip(names,counts):
print(name)
#결과
Cecilia
남궁만수
abc
리스트 컴프리헨션으로 리스트를 파생시킨 경우 각 리스트의 길이가 같은 경우가 많다.
긴 이터레이터의 뒷부분을 버리는 zip기능이 바람직하지 못하는 경우도 있다.
- 가장 짧은 이터레이터에 맞춰 길이를 제한하지 않고 길이가 서로 다른 이터레이터에 대해 루프를 수행하려면 itertools 내장 모듈의 zip_longes함수 사용
- 만약 리스트의 길이가 같지 않다면 itertools 내장 모듈에 들어 있는 zip_longest 대신 사용하는 것을 고려한다.
import itertools
from name, count in itertools.zip_longest(names, counts):
print(f'{name}: {count}')
Cecilia: 7
남궁민수: 4
abc: 3
Rosalind: None
zip_longest는 존재하지 않는 값을 fillvalue로 대신한다.
- fillvalue의 default는 None이다.