2017-08-15 30 views
3

__iter__()函數中使用發生器(yield)的優點是什麼?通過閱讀Python指南我明白「如果你想讓一個發生器向用戶公開額外的狀態,不要忘記,你可以很容易地將它作爲一個類來實現它,把發生器的功能代碼放在__iter__()方法中。」在__iter __()中使用yield的優點是什麼?

import io 

class playyield: 
    def __init__(self,fp): 
     self.completefp = fp 

    def __iter__(self): 
     for line in self.completefp: 
      if 'python' in line: 
       yield line 

if __name__ =='__main__': 
    with io.open(r'K:\Data\somefile.txt','r') as fp: 
     playyieldobj = playyield(fp) 
     for i in playyieldobj: 
      print I 

問題

  1. 是什麼額外的狀態意味着在這裏?
  2. __iter__()中使用yield而不是使用yield的單獨函數有什麼好處?
+1

因爲現在'playyield'是* *可迭代,但是你沒有寫一個*迭代器*類,從現在開始'playyied .__ iter__'返回一個生成器,它是一個迭代器。這很方便。 –

+0

你的問題不是提供整個上下文。你從Python Cookbook中提到的引用是關於問題**問題:**你想定義一個生成器函數,但它涉及到你想以某種方式向用戶公開的額外狀態。這裏的_extra state_表示與程序其他部分有關的其他信息。 –

+0

我還建議您查看[博客文章](http://nvie.com/posts/iterators-vs-generators/) –

回答

2

沒有發電機的功能,你就必須實現這樣的事情,如果你要遵循最佳做法:

In [7]: class IterableContainer: 
    ...:  def __init__(self, data=(1,2,3,4,5)): 
    ...:   self.data = data 
    ...:  def __iter__(self): 
    ...:   return IterableContainerIterator(self.data) 
    ...: 

In [8]: class IterableContainerIterator: 
    ...:  def __init__(self, data): 
    ...:   self.data = data 
    ...:   self._pos = 0 
    ...:  def __iter__(self): 
    ...:   return self 
    ...:  def __next__(self): 
    ...:   try: 
    ...:    item = self.data[self._pos] 
    ...:   except IndexError: 
    ...:    raise StopIteration 
    ...:   self._pos += 1 
    ...:   return item 
    ...: 

In [9]: container = IterableContainer() 

In [10]: for x in container: 
    ...:  print(x) 
    ...: 
1 
2 
3 
4 
5 

當然,上面的例子是人爲的,但希望你明白了吧。隨着發電機組,這可能僅僅是:

In [11]: class IterableContainer: 
    ...:  def __init__(self, data=(1,2,3,4,5)): 
    ...:   self.data = data 
    ...:  def __iter__(self): 
    ...:   for x in self.data: 
    ...:    yield x 
    ...: 
    ...: 

In [12]: list(IterableContainer()) 
Out[12]: [1, 2, 3, 4, 5] 

至於狀態,那麼,它的正是 - 對象可以有狀態,例如屬性。您可以在運行時操縱該狀態。您可以類似以下,雖然,我會說這是極不妥當:

In [19]: class IterableContainerIterator: 
    ...:  def __init__(self, data): 
    ...:   self.data = data 
    ...:   self._pos = 0 
    ...:  def __iter__(self): 
    ...:   return self 
    ...:  def __next__(self): 
    ...:   try: 
    ...:    item = self.data[self._pos] 
    ...:   except IndexError: 
    ...:    raise StopIteration 
    ...:   self._pos += 1 
    ...:   return item 
    ...:  def rewind(self): 
    ...:   self._pos = min(0, self._pos - 1) 
    ...: 

In [20]: class IterableContainer: 
    ...:  def __init__(self, data=(1,2,3,4,5)): 
    ...:   self.data = data 
    ...:  def __iter__(self): 
    ...:   return IterableContainerIterator(self.data) 
    ...: 

In [21]: container = IterableContainer() 

In [22]: it = iter(container) 

In [23]: next(it) 
Out[23]: 1 

In [24]: next(it) 
Out[24]: 2 

In [25]: it.rewind() 

In [26]: next(it) 
Out[26]: 1 

In [27]: next(it) 
Out[27]: 2 

In [28]: next(it) 
Out[28]: 3 

In [29]: next(it) 
Out[29]: 4 

In [30]: next(it) 
Out[30]: 5 

In [31]: it.rewind() 

In [32]: next(it) 
Out[32]: 1 
相關問題