为什么一些(但不是全部)Python 迭代器在用完后可以求和?
Why are some (but not all) Python iterators summable after being exhausted?
在 Python 中,迭代器旨在一次性使用。一旦迭代器引发了 StopIteration,它就不应该 return 任何更多值。然而,如果我定义一个自定义迭代器,似乎我仍然可以在它们耗尽后对值进行求和!
示例代码(Python 3.6.5,或将 __next__(self)
替换为 next(self)
以查看 Python 2.7.15 中的相同行为:
class CustomIterator:
def __iter__(self):
self.n=0
return self
def __next__(self):
self.n += 1
if self.n > 3:
raise StopIteration
return self.n
i1 = iter([1,2,3])
i2 = iter(CustomIterator())
print('Sum of i1 is {}'.format(sum(i1))) # returns 6 as expected
print('Sum of i1 is {}'.format(sum(i1))) # returns 0 because i1 is now exhausted
try:
print(next(i1))
except StopIteration:
print("i1 has raised StopIteration") # this exception happens
print('Sum of i1 is {}'.format(sum(i1))) # 0 again
print('Sum of i2 is {}'.format(sum(i2))) # returns 6 as expected
print('Sum of i2 is {}'.format(sum(i2))) # returns 6 again!
try:
print(next(i2))
except StopIteration:
print("i2 has raised StopIteration") # still get an exception
print('Sum of i2 is {}'.format(sum(i2))) # and yet we get 6 again
为什么 i1 和 i2 的行为不同? sum
是如何实现的一些技巧?我已经检查过 https://docs.python.org/3/library/functions.html#sum,它并没有给我很多继续下去的机会。
相关问题:
- Summing values in an Iterator
- Why can't I iterate twice over the same data?
- Python iterator is empty after performing some action on it
这些描述了内置迭代器的预期行为,但没有解释为什么我的自定义迭代器的行为不同。
问题是自定义迭代器正在 __iter__
方法内部初始化。即使 i2 = iter(CustomIterator())
包含对 iter
的显式调用,sum
函数(以及 min
、max
、for
等)仍将再次调用 i2.__iter__()
并重置 i2
.
有很多关于“如何制作 Python 迭代器”的教程,其中大约一半说“要制作迭代器,你只需要定义 iter
和next
方法”。虽然根据 the documentation 这在技术上是正确的,但有时会给您带来麻烦。在许多情况下,您还需要一个单独的 __init__
方法来初始化迭代器。
因此,要解决此问题,请将 CustomIterator
重新定义为:
class CustomIterator:
def __init__(self):
self.n=0
def __iter__(self):
return self
def __next__(self):
self.n += 1
if self.n > 3:
raise StopIteration
return self.n
i1 = iter([1,2,3])
i2 = CustomIterator() ### iter(...) is not needed here (but won't do any harm either)
然后 init
只在创建新迭代器时调用一次,重复调用 iter
不会重置迭代器。
在 Python 中,迭代器旨在一次性使用。一旦迭代器引发了 StopIteration,它就不应该 return 任何更多值。然而,如果我定义一个自定义迭代器,似乎我仍然可以在它们耗尽后对值进行求和!
示例代码(Python 3.6.5,或将 __next__(self)
替换为 next(self)
以查看 Python 2.7.15 中的相同行为:
class CustomIterator:
def __iter__(self):
self.n=0
return self
def __next__(self):
self.n += 1
if self.n > 3:
raise StopIteration
return self.n
i1 = iter([1,2,3])
i2 = iter(CustomIterator())
print('Sum of i1 is {}'.format(sum(i1))) # returns 6 as expected
print('Sum of i1 is {}'.format(sum(i1))) # returns 0 because i1 is now exhausted
try:
print(next(i1))
except StopIteration:
print("i1 has raised StopIteration") # this exception happens
print('Sum of i1 is {}'.format(sum(i1))) # 0 again
print('Sum of i2 is {}'.format(sum(i2))) # returns 6 as expected
print('Sum of i2 is {}'.format(sum(i2))) # returns 6 again!
try:
print(next(i2))
except StopIteration:
print("i2 has raised StopIteration") # still get an exception
print('Sum of i2 is {}'.format(sum(i2))) # and yet we get 6 again
为什么 i1 和 i2 的行为不同? sum
是如何实现的一些技巧?我已经检查过 https://docs.python.org/3/library/functions.html#sum,它并没有给我很多继续下去的机会。
相关问题:
- Summing values in an Iterator
- Why can't I iterate twice over the same data?
- Python iterator is empty after performing some action on it
这些描述了内置迭代器的预期行为,但没有解释为什么我的自定义迭代器的行为不同。
问题是自定义迭代器正在 __iter__
方法内部初始化。即使 i2 = iter(CustomIterator())
包含对 iter
的显式调用,sum
函数(以及 min
、max
、for
等)仍将再次调用 i2.__iter__()
并重置 i2
.
有很多关于“如何制作 Python 迭代器”的教程,其中大约一半说“要制作迭代器,你只需要定义 iter
和next
方法”。虽然根据 the documentation 这在技术上是正确的,但有时会给您带来麻烦。在许多情况下,您还需要一个单独的 __init__
方法来初始化迭代器。
因此,要解决此问题,请将 CustomIterator
重新定义为:
class CustomIterator:
def __init__(self):
self.n=0
def __iter__(self):
return self
def __next__(self):
self.n += 1
if self.n > 3:
raise StopIteration
return self.n
i1 = iter([1,2,3])
i2 = CustomIterator() ### iter(...) is not needed here (but won't do any harm either)
然后 init
只在创建新迭代器时调用一次,重复调用 iter
不会重置迭代器。