이것은 문서에zip
주어진 구현과 동일합니다.
def zip(*iterables):
# zip('ABCD', 'xy') --> Ax By
sentinel = object()
iterators = [iter(it) for it in iterables]
while iterators:
result = []
for it in iterators:
elem = next(it, sentinel)
if elem is sentinel:
return
result.append(elem)
yield tuple(result)
첫 번째 예에서 gen1 = my_gen(10)
및 gen2 = my_gen(8)
. 두 발전기는 모두 7 번째 반복까지 소비됩니다. 이제 8 번째 반복 gen1
호출 에서는 8 elem = next(it, sentinel)
을 반환하지만 gen2
호출 elem = next(it, sentinel)
할 때 sentinel
(이것이 gen2
소진 되었기 때문에 ) if elem is sentinel
반환되고 만족되고 함수는 return과 stop을 실행합니다. 이제 next(gen1)
9를 반환합니다.
두 번째 예에서 gen1 = gen(8)
및 gen2 = gen(10)
. 두 발전기는 모두 7 번째 반복까지 소비됩니다. 이제 8 번째 반복에서 gen1
호출 elem = next(it, sentinel)
하는 수익률 sentinel
(때문에이 점에 gen1
소진)과 if elem is sentinel
만족과 기능이 실행 반환 및 정지. 이제 next(gen2)
8을 반환합니다.
Mad Physicist 's answer 에서 영감을 얻은 이 Gen
래퍼를 사용 하여 이에 대응할 수 있습니다.
편집 : Jean-Francois T가 지적한 사례를 처리합니다 .
이터레이터에서 값이 소비되면 이터레이터에서 영원히 사라지고 이터레이터가 이터레이터를 다시 이터레이터에 다시 추가 할 수있는 적절한 돌연변이 방법이 없습니다. 한 가지 해결 방법은 마지막으로 소비 된 값을 저장하는 것입니다.
class Gen:
def __init__(self,iterable):
self.d = iter(iterable)
self.sentinal = object()
self.prev = self.sentinal
def __iter__(self):
return self
@property
def last_val_consumed(self):
if self.prev is None:
raise StopIteration
if self.prev == self.sentinal:
raise ValueError('Nothing has been consumed')
return self.prev
def __next__(self):
self.prev = next(self.d,None)
if self.prev is None:
raise StopIteration
return self.prev
예 :
# When `gen1` is larger than `gen2`
gen1 = Gen(range(10))
gen2 = Gen(range(8))
list(zip(gen1,gen2))
# [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6), (7, 7)]
gen1.last_val_consumed
# 8 #as it was the last values consumed
next(gen1)
# 9
gen1.last_val_consumed
# 9
# 2. When `gen1` or `gen2` is empty
gen1 = Gen(range(0))
gen2 = Gen(range(5))
list(zip(gen1,gen2))
gen1.last_val_consumed
# StopIteration error is raised
gen2.last_val_consumed
# ValueError is raised saying `ValueError: Nothing has been consumed`