如何实现容器对象的__iter __(self)(Python)
我写了一个自定义的容器对象。
根据这个页面 ,我需要在我的对象上实现这个方法:
__iter__(self)
但是,在Python参考手册中跟随迭代器types的链接后,没有给出如何实现自己的示例。
有人可以发布一个片段(或链接到资源),显示如何做到这一点?
我正在写的容器是一个映射(即通过唯一键存储值)。 字典可以像这样迭代:
for k, v in mydict.items()
在这种情况下,我需要能够在迭代器中返回两个元素(一个元组?)。 目前还不清楚如何实现这样一个迭代器(尽pipe已经提供了几个答案)。 有人可以请摆脱一些关于如何实现一个地图像容器对象的迭代器? (即像dict一样的自定义类)?
我通常会使用生成器函数。 每次使用yield语句时,都会将一个项目添加到序列中。
以下将创build一个返回5的迭代器,然后是some_list中的每个项目。
def __iter__(self): yield 5 for x in some_list: yield x
另一个select是从这里的`collections`模块中inheritance适当的抽象基类。
如果容器是自己的迭代器,则可以从collections.Iterator
inheritance。 那么你只需要实现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
或其他抽象基类inheritance(如果更合适)。 下面是一个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提请注意澄清迭代器与迭代器之间的区别,而不是迭代器。
通常__iter__()
只是返回self,如果你已经定义了next()方法(generator对象):
这里是一个发电机的虚拟示例:
class Test(object): def __init__(self, data): self.data = data def next(self): if not self.data: raise StopIteration return self.data.pop() def __iter__(self): return self
但__iter__()
也可以像这样使用: http : __iter__()
如果你的对象包含一组数据,你想绑定你的对象的iter,你可以作弊和做到这一点:
>>> class foo: def __init__(self, *params): self.data = params def __iter__(self): if hasattr(self.data[0], "__iter__"): return self.data[0].__iter__() return self.data.__iter__() >>> d=foo(6,7,3,8, "ads", 6) >>> for i in d: print i 6 7 3 8 ads 6
要回答关于映射的问题:您提供的__iter__
应该迭代映射的键 。 下面是一个简单的例子,它创build一个映射x -> x * x
并在Python3上扩展ABC映射。
import collections.abc class MyMap(collections.abc.Mapping): def __init__(self, n): self.n = n def __getitem__(self, key): # given a key, return it's value if 0 <= key < self.n: return key * key else: raise KeyError('Invalid key') def __iter__(self): # iterate over all keys for x in range(self.n): yield x def __len__(self): return self.n m = MyMap(5) for k, v in m.items(): print(k, '->', v) # 0 -> 0 # 1 -> 1 # 2 -> 4 # 3 -> 9 # 4 -> 16
如果你不想像其他人所说的那样inheritancedict
那么直接回答如何实现__iter__
这个自定义字典的粗糙例子:
class Attribute: def __init__(self, key, value): self.key = key self.value = value class Node(collections.Mapping): def __init__(self): self.type = "" self.attrs = [] # List of Attributes def __iter__(self): for attr in self.attrs: yield attr.key
这使用了一个生成器, 在这里很好地描述。
由于我们从Mapping
inheritance,所以还需要实现__getitem__
和__len__
:
def __getitem__(self, key): for attr in self.attrs: if key == attr.key: return attr.value raise KeyError def __len__(self): return len(self.attrs)
Python中的“可迭代接口”由next ()和iter ()两个方法组成。 下一个函数是最重要的,因为它定义了迭代器的行为 – 也就是说,该函数确定下一个应该返回的值。 iter ()方法用于重置迭代的起点。 通常,当init ()被用来设置起点时,你会发现iter ()可以返回self。
请参阅下面的代码来定义一个实现“可迭代接口”的类反转,并定义来自任何序列类的任何实例的迭代器。 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
一个可能适用于某些情况的选项是让你的自定义类inheritance dict
。 这似乎是一个合乎逻辑的select,如果它像一个字典行事; 也许它应该是一个字典。 这样,你可以免费得到类似字典的迭代。
class MyDict(dict): def __init__(self, custom_attribute): self.bar = custom_attribute mydict = MyDict('Some name') mydict['a'] = 1 mydict['b'] = 2 print mydict.bar for k, v in mydict.items(): print k, '=>', v
输出:
Some name a => 1 b => 2
例如,从字典inhert,修改它的iter
,例如,在for循环时跳过键2
# method 1 class Dict(dict): def __iter__(self): keys = self.keys() for i in keys: if i == 2: continue yield i # method 2 class Dict(dict): def __iter__(self): for i in super(Dict, self).__iter__(): if i == 2: continue yield i