如何为容器对象(Python)实现iter(self)
我已经编写了一个自定义容器对象 根据,我需要在我的对象上实现此方法:如何为容器对象(Python)实现iter(self),python,Python,我已经编写了一个自定义容器对象 根据,我需要在我的对象上实现此方法: __iter__(self) 但是,在Python参考手册中的链接之后,没有给出如何实现自己的示例 是否有人可以发布一个片段(或指向资源的链接),展示如何做到这一点 我正在编写的容器是一个映射(即,通过唯一键存储值)。 dicts可以这样迭代: for k, v in mydict.items() 在这种情况下,我需要能够在迭代器中返回两个元素(一个元组?)。 目前还不清楚如何实现这样一个迭代器(尽管已经提供了一些答案)。
__iter__(self)
但是,在Python参考手册中的链接之后,没有给出如何实现自己的示例
是否有人可以发布一个片段(或指向资源的链接),展示如何做到这一点
我正在编写的容器是一个映射(即,通过唯一键存储值)。
dicts可以这样迭代:
for k, v in mydict.items()
在这种情况下,我需要能够在迭代器中返回两个元素(一个元组?)。
目前还不清楚如何实现这样一个迭代器(尽管已经提供了一些答案)。有人能告诉我们如何为类似于映射的容器对象实现迭代器吗?(即,一个像dict一样工作的自定义类)?我通常会使用生成器函数。每次使用yield语句时,它都会向序列中添加一项 下面将创建一个迭代器,该迭代器生成5个,然后生成某个_列表中的每个项
def __iter__(self):
yield 5
yield from some_list
在3.3之前,的收益率不存在,因此您必须执行以下操作:
def __iter__(self):
yield 5
for x in some_list:
yield x
通常,如果已经定义了next()方法(生成器对象),只需返回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
但是\uuu iter\uuu()
也可以这样使用:
如果您的对象包含要将对象的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
另一种选择是从文档中的`集合'模块继承适当的抽象基类 如果容器是自己的迭代器,则可以从
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
当您查看<代码>集合>代码>模块时,请考虑从<代码>序列>代码>、<代码>映射> /代码>或另一个抽象基类继承,如果这更合适的话。下面是一个
序列
子类的示例:
>>> 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提请我注意澄清迭代器与可重用容器(而非迭代器)之间的区别。要回答有关映射的问题,您提供的
\u iter\u
应该迭代映射键。下面是一个简单的示例,它创建一个映射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
import collections.abc
类MyMap(collections.abc.Mapping):
定义初始化(self,n):
self.n=n
def u getitem(self,key):#给定一个键,返回它的值
如果0
# 1 -> 1
# 2 -> 4
# 3 -> 9
# 4 -> 16
在某些情况下,一个可行的选项是使自定义类继承dict
。这似乎是一个合乎逻辑的选择,如果它像一个口述;也许它应该是一个dict。这样,你就可以免费得到类似dict的迭代
类MyDict(dict):
def uuu init uuu(自我、自定义属性):
self.bar=自定义_属性
mydict=mydict('某个名称')
mydict['a']=1
mydict['b']=2
打印mydict.bar
对于mydict.items()中的k,v:
打印k,“=>”,v
输出:
一些名字
a=>1
b=>2
如果您不想像其他人建议的那样从dict
继承,下面是如何实现\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
的问题的直接答案,这是一
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
它使用了一个发电机,这是很好的描述
由于我们是从映射继承的
,因此您还需要实现\uuu getitem\uuuuuuuu
和\uuu len\uuuuu
:
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)
例如,从dict输入时,修改其
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
python中的“iterable接口”由两个方法组成\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu函数是最重要的,因为它定义了迭代器行为-也就是说,该函数确定了下一步应该返回的值。\uuu iter\uu()
方法用于重置迭代的起点。通常,当使用\uuuu init\uuuu()
设置起点时,您会发现\uuuu iter\uuuu()
可以返回self
请参阅下面的代码,以定义一个类Reverse,该类实现“iterable接口”,并在任何sequence类的任何实例上定义迭代器。\uuuuuuuuuuuuuuuuuuuuuuuuu()
方法从序列的末尾开始,并按与序列相反的顺序返回值。请注意,来自实现“序列接口”的类的实例必须定义\uuu len\uuu()
和\uuu getitem\uuu()
方法
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
这就是你对迭代器类所做的,但问题是关于容器对象的。在Python 3和更高版本中仍然是这样吗?不要混淆iterable对象和迭代器——你不想从迭代器继承不是迭代器本身的iterable对象(例如容器)@Glenn:你是对的,一个典型的容器不是迭代器。我只是回答了这个问题,其中提到了迭代器类型。正如我在答案的最后所说,我认为从一个更合适的选择继承遗产更合适。我将在回答中澄清这一点。似乎使用.pop()实现下一个函数会导致一些不希望出现的效果。首先,迭代器以相反的顺序返回iterable对象的元素,其次,在迭代过程中,可发出的对象被耗尽。还有其他方便的方法吗?不要检查hasattr
,而是使用try/except AttributeError
是否需要提出StopIteration?这是如何区分何时停止的?@JonathanLeaders当一些
列表中的所有元素都已生成时。实际上——在这个用例中——如果您希望停止,您只需要启动StopIteration