如何为容器对象(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