2017-08-15 93 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 
相关问题