2017-03-02 80 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