2017-03-02 38 views
4

所以我一直在写迭代器,并且我认为我理解了它们。但是我今晚一直在努力解决一些问题,而我越玩越容易陷入困境。迭代器协议。它是黑魔法吗?

我认为迭代器必须实现__iter__next(或__next__)。而且,当您第一次尝试迭代迭代器时,将调用__iter__方法,然后next将被调用,直到StopIteration被引发。

当我运行这段代码虽然

class Iter(object): 

    def __iter__(self): 
     return iter([2, 4, 6]) 

    def next(self): 
     for y in [1, 2, 3]: 
      return y 

iterable = Iter() 
for x in iterable: 
    print(x) 

输出为2 4 6。因此正在调用__iter__,但不是next。这似乎与我找到的文档相匹配here。但是那样会在我的脑海里提出更多的问题。

具体来说,什么是容器类型和迭代器之间的区别,如果它不是next执行?我怎么知道我的班级将会得到怎样的待遇?最重要的是,如果我想编写一个在使用for x in Iter()时调用next方法的课程,我该怎么做?

回答

6

列表是可迭代,但它不是迭代器。比较和对比:

>>> type([]) 
list 
>>> type(iter([])) 
list_iterator 

调用iter在列表中创建并返回一个新的迭代器对象遍历该列表中的内容。

在你的对象,你只返回一个列表迭代器,具体迭代器在列表[2, 4, 6],使对象一无所知产生元素1,2,3

def __iter__(self): 
    return iter([2, 4, 6]) # <-- you're returning the list iterator, not your own 

这里是符合一个更根本的实现到Python 2中的迭代器协议,它不会依赖列表迭代器,生成器或任何其他任何东西来混淆事物。

class Iter(object): 

    def __iter__(self): 
     self.val = 0 
     return self 

    def next(self): 
     self.val += 1 
     if self.val > 3: 
      raise StopIteration 
     return self.val 
+0

我想我回来了。所以所有迭代器都是迭代器,但并非所有迭代器都是迭代器。当我遍历一个迭代器时,我真的在遍历它的'iter'方法返回。哪一个可以通过一个迭代器或一个生成器? –

+0

正确。所有迭代器都是可迭代的。并不是所有的迭代器都是迭代器(例如,列表是可迭代的,但它们不是迭代器,因为它们不实现“next”)。通过在对象上调用'iter()'返回任何对象上的对象的迭代。 *必须*返回一个迭代器(生成器是一种迭代器)。 – wim

+0

谢谢。我想在一开始就知道这一切,但我也在一开始就想到了,但也想到了其他一些非常非常错误的事情。 –

2

根据您链接到的文档,迭代器的__iter__方法应该返回自身。所以你的迭代器根本就不是一个迭代器:当for调用__iter__来获得迭代器时,你给它iter([2,4,6]),但你应该给它self

(另外,我不认为你的next方法做你想要什么:它的每一个,它被称为时间返回1,从来没有提出StopIteration所以,如果你固定__iter__,那么你的迭代器会在一个无限流的迭代器。的,而不是在有限的名单[1, 2, 3]。但这是一个侧面问题。)

+0

是的,我知道这段代码是无稽之谈。我试图向自己证明的一点是,迭代的对象是我的'__iter__'方法正在返回,并且我的'next'方法根本不会被调用。也许我只是累了,应该睡觉,但我真的不明白'next'方法是如何被调用的。 –

+0

@GreeTreePython:被调用的'next'方法是'__iter__'返回的迭代器上的'next'方法。 – ruakh