分离 __iter__ 和 __next__ 方法
Separating the __iter__ and __next__ methods
在Python 3 中,通过同时定义__iter__
和__next__
方法,使class 成为可迭代对象和迭代器是标准过程。但是我很难解决这个问题。以这个例子为例,它创建了一个只产生偶数的迭代器:
class EvenNumbers:
def __init__(self, max_):
self.max_ = max_
def __iter__(self):
self.n = 0
return self
def __next__(self):
if self.n <= self.max_: # edit: self.max --> self.max_
result = 2 * self.n
self.n += 1
return result
raise StopIteration
instance = EvenNumbers(4)
for entry in instance:
print(entry)
据我所知(如果我错了请纠正我),当我创建循环时,通过调用类似 itr = iter(instance)
的方法创建一个迭代器,它在内部调用 __iter__
方法。这应该是 return 一个迭代器对象(该实例是由于定义了 __next__
,因此我只能 return self)。要从中获取元素,将调用 next(itr)
直到引发异常。
我现在的问题是:__iter__
和__next__
是否以及如何分开,以便在其他地方定义后一个函数的内容?这什么时候有用?我知道我必须更改 __iter__
以便它 return 是一个迭代器。
顺便说一句,这样做的想法来自这个网站 (LINK),它没有说明如何实现它。
听起来你混淆了迭代器和迭代器。 Iterables 有一个 __iter__
方法,它 return 是一个迭代器。迭代器有一个 __next__
方法,它 return 要么是它们的下一个值,要么引发一个 StopIteration
。现在在 python 中 stated 迭代器也是可迭代的(但反之亦然)并且 iter(iterator) is iterator
所以迭代器 itr
应该只 return本身来自它的 __iter__
方法。
Iterators are required to have an __iter__()
method that returns the iterator object itself so every iterator is also iterable and may be used in most places where other iterables are accepted
在代码中:
class MyIter:
def __iter__(self):
return self
def __next__(self):
# actual iterator logic
如果你想做一个自定义的迭代器class,最简单的方法是从collections.abc.Iterator
继承,你可以看到上面定义了__iter__
(它也是一个子class,共 collections.abc.Iterable
)。那么你只需要
class MyIter(collections.abc.Iterator):
def __next__(self):
...
当然有一种更简单的方法来制作迭代器,那就是使用生成器函数
def fib():
a = 1
b = 1
yield a
yield b
while True:
b, a = a + b, b
yield b
list(itertools.takewhile(lambda x: x < 100, fib()))
# --> [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
仅供参考,这是抽象迭代器和可迭代的(简化)代码
from abc import ABC, abstractmethod
class Iterable(ABC):
@abstractmethod
def __iter__(self):
'Returns an instance of Iterator'
pass
class Iterator(Iterable, ABC):
@abstractmethod
def __next__(self):
'Return the next item from the iterator. When exhausted, raise StopIteration'
pass
# overrides Iterable.__iter__
def __iter__(self):
return self
我想我现在已经掌握了这个概念,即使我不完全理解@FHTMitchell 文档中的段落。我遇到了一个关于如何分离这两种方法的示例,并想记录下来。
我发现的是一个非常basic tutorial明确区分了iterable和iterator(这是我混淆的原因)。
基本上,您首先将 iterable 定义为单独的 class:
class EvenNumbers:
def __init__(self, max_):
self.max = max_
def __iter__(self):
self.n = 0
return EvenNumbersIterator(self)
__iter__
方法只需要一个定义了 __next__
方法的对象。因此,您可以这样做:
class EvenNumbersIterator:
def __init__(self, source):
self.source = source
def __next__(self):
if self.source.n <= self.source.max:
result = 2 * self.source.n
self.source.n += 1
return result
else:
raise StopIteration
这将迭代器部分与可迭代的部分分开 class。现在有意义的是,如果我在可迭代 class 中定义 __next__
,我必须 return 对实例本身的引用,因为它基本上一次执行 2 个作业。
在Python 3 中,通过同时定义__iter__
和__next__
方法,使class 成为可迭代对象和迭代器是标准过程。但是我很难解决这个问题。以这个例子为例,它创建了一个只产生偶数的迭代器:
class EvenNumbers:
def __init__(self, max_):
self.max_ = max_
def __iter__(self):
self.n = 0
return self
def __next__(self):
if self.n <= self.max_: # edit: self.max --> self.max_
result = 2 * self.n
self.n += 1
return result
raise StopIteration
instance = EvenNumbers(4)
for entry in instance:
print(entry)
据我所知(如果我错了请纠正我),当我创建循环时,通过调用类似 itr = iter(instance)
的方法创建一个迭代器,它在内部调用 __iter__
方法。这应该是 return 一个迭代器对象(该实例是由于定义了 __next__
,因此我只能 return self)。要从中获取元素,将调用 next(itr)
直到引发异常。
我现在的问题是:__iter__
和__next__
是否以及如何分开,以便在其他地方定义后一个函数的内容?这什么时候有用?我知道我必须更改 __iter__
以便它 return 是一个迭代器。
顺便说一句,这样做的想法来自这个网站 (LINK),它没有说明如何实现它。
听起来你混淆了迭代器和迭代器。 Iterables 有一个 __iter__
方法,它 return 是一个迭代器。迭代器有一个 __next__
方法,它 return 要么是它们的下一个值,要么引发一个 StopIteration
。现在在 python 中 stated 迭代器也是可迭代的(但反之亦然)并且 iter(iterator) is iterator
所以迭代器 itr
应该只 return本身来自它的 __iter__
方法。
Iterators are required to have an
__iter__()
method that returns the iterator object itself so every iterator is also iterable and may be used in most places where other iterables are accepted
在代码中:
class MyIter:
def __iter__(self):
return self
def __next__(self):
# actual iterator logic
如果你想做一个自定义的迭代器class,最简单的方法是从collections.abc.Iterator
继承,你可以看到上面定义了__iter__
(它也是一个子class,共 collections.abc.Iterable
)。那么你只需要
class MyIter(collections.abc.Iterator):
def __next__(self):
...
当然有一种更简单的方法来制作迭代器,那就是使用生成器函数
def fib():
a = 1
b = 1
yield a
yield b
while True:
b, a = a + b, b
yield b
list(itertools.takewhile(lambda x: x < 100, fib()))
# --> [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
仅供参考,这是抽象迭代器和可迭代的(简化)代码
from abc import ABC, abstractmethod
class Iterable(ABC):
@abstractmethod
def __iter__(self):
'Returns an instance of Iterator'
pass
class Iterator(Iterable, ABC):
@abstractmethod
def __next__(self):
'Return the next item from the iterator. When exhausted, raise StopIteration'
pass
# overrides Iterable.__iter__
def __iter__(self):
return self
我想我现在已经掌握了这个概念,即使我不完全理解@FHTMitchell 文档中的段落。我遇到了一个关于如何分离这两种方法的示例,并想记录下来。
我发现的是一个非常basic tutorial明确区分了iterable和iterator(这是我混淆的原因)。
基本上,您首先将 iterable 定义为单独的 class:
class EvenNumbers:
def __init__(self, max_):
self.max = max_
def __iter__(self):
self.n = 0
return EvenNumbersIterator(self)
__iter__
方法只需要一个定义了 __next__
方法的对象。因此,您可以这样做:
class EvenNumbersIterator:
def __init__(self, source):
self.source = source
def __next__(self):
if self.source.n <= self.source.max:
result = 2 * self.source.n
self.source.n += 1
return result
else:
raise StopIteration
这将迭代器部分与可迭代的部分分开 class。现在有意义的是,如果我在可迭代 class 中定义 __next__
,我必须 return 对实例本身的引用,因为它基本上一次执行 2 个作业。