我写了一个自定义容器对象。
根据this page,我需要在我的对象上实现此方法:
__iter__(self)
但是,在跟进Python参考手册中Iterator Types的链接后,没有给出如何实现自己的链接的示例。
有人可以发布一个代码段(或指向资源的链接),它会显示如何执行此操作吗?
我正在写的容器是一张地图(即通过唯一键存储值)。 dicts可以这样迭代:
for k, v in mydict.items()
在这种情况下,我需要能够在迭代器中返回两个元素(一个元组?)。 目前尚不清楚如何实现这样的迭代器(尽管已经提供了几个答案)。有人可以更多地了解如何为类似地图的容器对象实现迭代器吗? (即一个像dict一样的自定义类)?
答案 0 :(得分:92)
我通常会使用生成器功能。每次使用yield语句时,它都会在序列中添加一个项目。
以下将创建一个迭代器,它返回some_list中的五个,然后返回每个项目。
def __iter__(self):
yield 5
yield from some_list
3.3之前,yield from
不存在,所以你必须这样做:
def __iter__(self):
yield 5
for x in some_list:
yield x
答案 1 :(得分:24)
另一种选择是从`collections模块中继承适当的抽象基类,如文档here所示。
如果容器是它自己的迭代器,你可以继承
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
NB :感谢Glenn Maynard引起我的注意,一方面需要澄清迭代器与另一方面迭代器而不是迭代器之间的区别。
答案 2 :(得分:12)
通常__iter__()
只返回self:
这是一个生成器的虚拟示例:
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://mail.python.org/pipermail/tutor/2006-January/044455.html
答案 3 :(得分:10)
如果你的对象包含一组你希望绑定你的对象的数据,你可以作弊并这样做:
>>> 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
答案 4 :(得分:6)
"可迭代界面"在python中包含两个方法__next__()
和__iter__()
。 __next__
函数是最重要的,因为它定义了迭代器行为 - 也就是说,函数确定接下来应返回的值。 __iter__()
方法用于重置迭代的起始点。通常,当__iter__()
用于设置起点时,您会发现__init__()
可以返回自我。
请参阅以下代码以定义实现"可迭代接口的类反向"并在任何序列类的任何实例上定义迭代器。 __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
答案 5 :(得分:5)
要回答有关映射的问题:您提供的__iter__
应该迭代映射的键。以下是一个创建映射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
答案 6 :(得分:4)
如果您不想像其他人所建议的那样继承dict
,请直接回答有关如何为自定义字典的粗略示例实现__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
使用生成器,这是一个很好的描述here。
由于我们要继承Mapping
,您还需要实施__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)
答案 7 :(得分:1)
可能适用于某些情况的一个选项是从dict
制作自定义类继承。如果它像一个字典,它似乎是一个合乎逻辑的选择;也许它应该是一个字典。这样,你就可以免费获得类似dict的迭代。
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
答案 8 :(得分:1)
来自dict的inhert示例,修改其iter
,例如,在for 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