在 __iter__() 中使用 yield 有什么好处?
What's the advantage of using yield in __iter__()?
在 __iter__()
函数中使用生成器 (yield
) 有什么好处?阅读 Python Cookbook 后,我明白“如果你想让生成器向用户公开额外的状态,请不要忘记你可以轻松地
将其实现为 class,将生成器函数代码放在 __iter__()
方法中。"
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
问题:
- extra state 在这里是什么意思?
- 在
__iter__ ()
中使用 yield
而不是为 yield
使用单独的函数有什么好处?
没有生成器函数,如果您想遵循最佳实践,则必须实现类似的东西:
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
在 __iter__()
函数中使用生成器 (yield
) 有什么好处?阅读 Python Cookbook 后,我明白“如果你想让生成器向用户公开额外的状态,请不要忘记你可以轻松地
将其实现为 class,将生成器函数代码放在 __iter__()
方法中。"
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
问题:
- extra state 在这里是什么意思?
- 在
__iter__ ()
中使用yield
而不是为yield
使用单独的函数有什么好处?
没有生成器函数,如果您想遵循最佳实践,则必须实现类似的东西:
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