如何为容器对象实现 __iter__(self) (Python)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4019971/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to implement __iter__(self) for a container object (Python)
提问by skyeagle
I have written a custom container object.
我编写了一个自定义容器对象。
According to this page, I need to implement this method on my object:
根据这个页面,我需要在我的对象上实现这个方法:
__iter__(self)
However, upon following up the link to Iterator Typesin the Python reference manual, there are no examples given of how to implement your own.
但是,在跟踪Python 参考手册中迭代器类型的链接时,没有给出如何实现自己的示例。
Can someone post a snippet (or link to a resource), that shows how to do this?
有人可以发布一个片段(或资源链接),显示如何做到这一点?
The container I am writing, is a map (i.e. stores values by unique keys). dicts can be iterated like this:
我正在编写的容器是一个映射(即通过唯一键存储值)。dicts 可以这样迭代:
for k, v in mydict.items()
In this case I need to be able to return two elements (a tuple?) in the iterator. It is still not clear how to implement such an iterator (despite the several answers that have been kindly provided). Could someone please shed some more light on how to implement an iterator for a map-like container object? (i.e. a custom class that acts like a dict)?
在这种情况下,我需要能够在迭代器中返回两个元素(一个元组?)。仍然不清楚如何实现这样的迭代器(尽管已经提供了几个答案)。有人可以更详细地说明如何为类似地图的容器对象实现迭代器吗?(即像字典一样的自定义类)?
回答by mikerobi
I normally would use a generator function. Each time you use a yield statement, it will add an item to the sequence.
我通常会使用生成器函数。每次使用 yield 语句时,它都会向序列中添加一个项目。
The following will create an iterator that yields five, and then every item in some_list.
下面将创建一个迭代器,它产生五个,然后是 some_list 中的每个项目。
def __iter__(self):
yield 5
yield from some_list
Pre-3.3, yield fromdidn't exist, so you would have to do:
Pre-3.3,yield from不存在,所以你必须做:
def __iter__(self):
yield 5
for x in some_list:
yield x
回答by mouad
usually __iter__()just return self if you have already define the next() method (generator object):
__iter__()如果您已经定义了 next() 方法(生成器对象),通常只返回 self :
here is a Dummy example of a 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
but __iter__()can also be used like this:
http://mail.python.org/pipermail/tutor/2006-January/044455.html
但__iter__()也可以这样使用:http:
//mail.python.org/pipermail/tutor/2006-January/044455.html
回答by Squirrelsama
If your object contains a set of data you want to bind your object's iter to, you can cheat and do this:
如果您的对象包含一组您希望将对象的 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
回答by Muhammad Alkarouri
Another option is to inherit from the appropriate abstract base class from the `collections module as documented here.
另一种选择是从此处记录的`collections 模块中继承适当的抽象基类。
In case the container is its own iterator, you can inherit from
collections.Iterator. You only need to implement the nextmethod then.
如果容器是它自己的迭代器,您可以从
collections.Iterator. 您只需要实现该next方法即可。
An example is:
一个例子是:
>>> 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
While you are looking at the collectionsmodule, consider inheriting from Sequence, Mappingor another abstract base class if that is more appropriate. Here is an example for a Sequencesubclass:
当你正在寻找的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: Thanks to Glenn Maynard for drawing my attention to the need to clarify the difference between iterators on the one hand and containers that are iterables rather than iterators on the other.
注意:感谢 Glenn Maynard 让我注意到一方面需要澄清迭代器与可迭代容器而不是迭代器之间的区别。
回答by Juan A. Navarro
To answer the question about mappings: your provided __iter__should iterate over the keysof the mapping. The following is a simple example that creates a mapping x -> x * xand works on Python3 extending the ABC mapping.
回答有关映射的问题:您提供的__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
回答by Eddified
One option that might work for some cases is to make your custom class inheritfrom dict. This seems like a logical choice if it acts like a dict; maybe it should bea dict. This way, you get dict-like iteration for free.
可能适用于某些情况的一种选择是让您的自定义类继承自dict. 如果它表现得像一个 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
Output:
输出:
Some name
a => 1
b => 2
回答by jfritz42
In case you don't want to inherit from dictas others have suggested, here is direct answer to the question on how to implement __iter__for a crude example of a custom dict:
如果您不想像dict其他人建议的那样继承,这里是有关如何实现__iter__自定义 dict 的粗略示例的问题的直接答案:
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
That uses a generator, which is well described here.
使用一台发电机,这是很好的描述在这里。
Since we're inheriting from Mapping, you need to also implement __getitem__and __len__:
由于我们继承自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)
回答by WeizhongTu
example for inhert from dict, modify its iter, for example, skip key 2when in for loop
例如从 dict 中继承,修改其iter,例如,2在 for 循环中跳过键
# 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
回答by FredAKA
The "iterable interface" in python consists of two methods __next__()and __iter__(). The __next__function is the most important, as it defines the iterator behavior - that is, the function determines what value should be returned next. The __iter__()method is used to reset the starting point of the iteration. Often, you will find that __iter__()can just return self when __init__()is used to set the starting point.
python 中的“可迭代接口”由两个方法__next__()和__iter__(). 该__next__功能是最重要的,因为它规定了迭代器的行为-也就是函数确定什么样的价值应该被下一个返回。该__iter__()方法用于重置迭代的起点。很多时候,你会发现 __iter__()在__init__()用来设置起点的时候就可以只返回 self了。
See the following code for defining a Class Reverse which implements the "iterable interface" and defines an iterator over any instance from any sequence class. The __next__()method starts at the end of the sequence and returns values in reverse order of the sequence. Note that instances from a class implementing the "sequence interface" must define a __len__()and a __getitem__()method.
请参阅以下用于定义 Class 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

