为什么类需要__iter __()来返回迭代器?

时间:2016-11-05 15:15:30

标签: python class python-3.x iterator

为什么类需要定义__iter__()返回self,以获取类的迭代器?

class MyClass:
    def __init__(self):
        self.state = 0

    def __next__(self):
        self.state += 1
        if self.state > 4:
            raise StopIteration
        return self.state

myObj = MyClass()
for i in myObj:
    print(i)

控制台日志:

Traceback (most recent call last):
   for i in myObj:
TypeError: 'MyClass' object is not iterable

回答https://stackoverflow.com/a/9884259/4515198

  

迭代器是具有下一个(Python 2)或__next__(Python 3)方法的对象。

添加以下内容的任务:

def __iter__(self):
   return self

是返回迭代器,或者是类的对象,它定义了__next__()方法。

但是,当MyClass在行myObj = MyClass()中实例化时,不是返回已由__next__()方法完成的MyClass对象(定义{{​​1}}方法)的任务?

定义__new__()方法的类的对象不是自己的迭代器吗?

我已经研究了问题What is the use of returning self in the __iter__ method?Build a Basic Python Iterator,但我仍然无法理解让__next__()方法返回自我的原因。

2 个答案:

答案 0 :(得分:9)

为什么 __ iter __()方法是必要的问题的答案是 for-loops 总是从在对象上调用 iter() 来获取迭代器。这就是为什么即使是iterator也需要一个 __ iter __()方法来处理for循环。在 for 调用 iter()之后,它会在生成的迭代器上调用 __ next __()来获取值。

创建iterables和迭代器的规则是:

1)Iterables有一个返回迭代器的 __ iter __()方法。

2)迭代器有一个 __ next __()方法,它返回一个更新状态的值,并在完成时引发 StopIteration

3)迭代器本身有一个返回 self __ iter __()方法。这意味着所有迭代器都是可自我迭代的。

对于具有返回 self __ iter __()方法的迭代器,最后一条规则的好处是它允许我们来传递部分消耗的迭代器

>>> s = 'hello world'
>>> it = iter(s)
>>> next(it)
'h'
>>> next(it)
'e'
>>> list(it)     # Doesn't start from the beginning
['l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd']

这是另一个依赖于迭代器可以自动迭代而不重新启动的例子:

>>> s = 'hello world'
>>> it = iter(s)
>>> list(zip(it, it))
[('h', 'e'), ('l', 'l'), ('o', ' '), ('w', 'o'), ('r', 'l')]

备注:

1)制作可迭代的另一种方法是提供 __ getitem __()方法,该方法接受连续索引并在完成时引发 IndexError 。这就是在Python 2中迭代 str 对象的方式。

2)像文件这样的对象是它们自己的迭代器。这意味着您可以直接在文件对象上调用 next()。它还意味着文件不能有多个独立的迭代器(文件对象本身具有跟踪文件中位置的状态)。

3)上面描述的迭代器设计模式不是Python特有的。它是许多OOP语言的通用设计模式:https://en.wikipedia.org/wiki/Iterator_pattern

答案 1 :(得分:4)

  

已经由__new__()方法

完成了

不,__new__只是另一种方法,它不会自动为对象创建__iter__

  

赢得定义__next__()方法的类的对象,自己是迭代器吗?

不一定,因为您定义__next__而非__iter__的第一堂课显示。如果您需要支持迭代,则__next__ 需要,因为它会生成值。 __iter__需要for,因为它在__next__语句中调用了一个对象,以便它获得一个迭代器。

你可以拥有一个只定义__iter__并且有些工作(它是有限的)的类,但它需要从某些人MyClass返回。例如,类CustomIter返回仅定义__next__的类class MyClass: def __iter__(self): return CustomIter() class CustomIter(object): def __init__(self): self.state = 0 def __next__(self): self.state += 1 if self.state > 4: raise StopIteration return self.state

__iter__

您需要在对象上定义__next__,该对象将返回定义__iter__的另一个对象(可能是其自身)。

如果您的班级将def __iter__(self): return self 定义为:

__next__

然后您需要在type(self)(该类)上定义__next__,因为您返回实例本身。 self将调用__iter__,直到无法生成更多值。

另一种情况是__next__只返回另一个定义__iter__的对象(根据我的第一个例子)。您也可以通过使class MyClass: def __init__(self): self.state = 0 def __iter__(self): for i in range(10): yield i 生成器来实现。

例如:

__next__

没有定义iter。当g = iter(MyClass()) 被调用时:

g

它返回定义__next__的生成器g = iter(MyClass()) g.__next__() # 0 g.__next__() # 1

vector<int> visited(50001);
map< pair<ll,ll> , ll> mymap;
map<ll, vector<ll> > graph;

void calc(ll start,ll node)
{
    visited[node]=1;
    vector<ll>::iterator it;
    for (it = graph[node].begin(); it != graph[node].end(); ++it)
    {
        if (!visited[*it])
        {
            ans+=mymap[make_pair(node,*it)];
            mymap[make_pair(start,*it)]=ans;
            calc(start, *it);
            ans-=mymap[make_pair(node,*it)];
        }
    }
}