如何为容器对象实现__iter__(self)(Python)
我写了一个自定义的容器对象。
根据这个页面,我需要在我的对象上实现这个方法:
__iter__(self)
但是,当我跟进链接到迭代器类型的Python参考手册时,里面没有给出如何实现自己的迭代器的例子。
有没有人能发一段代码(或者链接到一个资源),展示一下怎么做?
我正在写的容器是一个映射(也就是通过唯一的键来存储值)。字典可以这样迭代:
for k, v in mydict.items()
在这种情况下,我需要能够在迭代器中返回两个元素(一个元组?)。尽管已经有好心人提供了几个答案,但我仍然不清楚如何实现这样的迭代器。能不能请大家再多解释一下,如何为一个类似于映射的容器对象实现一个迭代器?(也就是一个像字典一样工作的自定义类)
9 个回答
在Python中,“可迭代接口”由两个方法组成:__next__()
和__iter__()
。其中,__next__
函数是最重要的,因为它定义了迭代器的行为,也就是说,这个函数决定了下一个返回的值是什么。__iter__()
方法则用于重置迭代的起始点。通常情况下,你会发现,当使用__init__()
来设置起始点时,__iter__()
可以直接返回自身(self)。
下面的代码展示了如何定义一个名为Reverse的类,这个类实现了“可迭代接口”,并为任何序列类的实例定义了一个迭代器。__next__()
方法从序列的末尾开始,并以相反的顺序返回值。需要注意的是,实现“序列接口”的类的实例必须定义__len__()
和__getitem__()
方法。
class Reverse:
"""Iterator for looping over a sequence backwards."""
def __init__(self, seq):
self.data = seq
self.index = len(seq)
def __iter__(self):
return self
def __next__(self):
if self.index == 0:
raise StopIteration
self.index = self.index - 1
return self.data[self.index]
>>> rev = Reverse('spam')
>>> next(rev) # note no need to call iter()
'm'
>>> nums = Reverse(range(1,10))
>>> next(nums)
9
另一种选择是从`collections`模块中的合适抽象基类继承,具体可以参考这里的文档。
如果你的容器本身就是一个迭代器,你可以从collections.Iterator
继承。这样你只需要实现next
这个方法就可以了。
下面是一个例子:
>>> from collections import Iterator
>>> class MyContainer(Iterator):
... def __init__(self, *data):
... self.data = list(data)
... def next(self):
... if not self.data:
... raise StopIteration
... return self.data.pop()
...
...
...
>>> c = MyContainer(1, "two", 3, 4.0)
>>> for i in c:
... print i
...
...
4.0
3
two
1
在查看collections
模块时,如果更合适的话,可以考虑从Sequence
、Mapping
或其他抽象基类继承。这里有一个Sequence
子类的例子:
>>> from collections import Sequence
>>> class MyContainer(Sequence):
... def __init__(self, *data):
... self.data = list(data)
... def __getitem__(self, index):
... return self.data[index]
... def __len__(self):
... return len(self.data)
...
...
...
>>> c = MyContainer(1, "two", 3, 4.0)
>>> for i in c:
... print i
...
...
1
two
3
4.0
注意: 感谢Glenn Maynard提醒我需要澄清迭代器和可迭代容器之间的区别。
我通常会使用生成器函数。每次你使用yield语句时,它会把一个项目添加到序列中。
下面的代码会创建一个迭代器,它会先返回数字五,然后返回some_list中的每一个项目。
def __iter__(self):
yield 5
yield from some_list
在Python 3.3之前,yield from
这个功能是不存在的,所以你必须这样做:
def __iter__(self):
yield 5
for x in some_list:
yield x