你如何在Python中创建像xrange这样的重复生成器?例如,如果我这样做:
>>> m = xrange(5)
>>> print list(m)
>>> print list(m)
Run Code Online (Sandbox Code Playgroud)
我两次得到相同的结果 - 数字0..4.但是,如果我尝试使用yield:
>>> def myxrange(n):
... i = 0
... while i < n:
... yield i
... i += 1
>>> m = myxrange(5)
>>> print list(m)
>>> print list(m)
Run Code Online (Sandbox Code Playgroud)
我第二次尝试迭代m,我什么都没回来 - 一个空列表.
有没有一种简单的方法可以创建像xrange那样的带有yield或生成器理解的重复生成器?我找到了Python跟踪器问题的解决方法,该问题使用装饰器将生成器转换为迭代器.每次开始使用它时都会重新启动,即使您上次没有使用所有值,就像xrange一样.我也提出了我自己的装饰器,基于相同的想法,实际上返回一个生成器,但一个可以在抛出StopIteration异常后重新启动:
@decorator.decorator
def eternal(genfunc, *args, **kwargs):
class _iterable:
iter = None
def __iter__(self): return self
def next(self, *nargs, **nkwargs):
self.iter = self.iter or genfunc(*args, **kwargs):
try:
return self.iter.next(*nargs, **nkwargs)
except StopIteration:
self.iter = None
raise
return _iterable()
Run Code Online (Sandbox Code Playgroud)
是否有更好的方法来解决问题,仅使用产量和/或发电机理解?或者内置于Python中的东西?所以我不需要滚动自己的类和装饰器?
u0b34a0f6ae的评论指出了我误解的根源:
xrange(5)不返回迭代器,它创建一个xrange对象.xrange对象可以像字典一样迭代,不止一次.
我的"永恒"函数完全是通过像迭代器/生成器(__iter__返回self)而不是像集合/ xrange(__iter__返回一个新的迭代器)那样吠叫错误的树.
Joh*_*kin 17
不是直接的.允许生成器用于实现协同例程,资源管理等的部分灵活性是它们始终是一次性的.一旦运行,就无法重新运行发电机.您必须创建一个新的生成器对象.
但是,您可以创建自己的类来覆盖__iter__().它将像一个可重用的生成器:
def multigen(gen_func):
class _multigen(object):
def __init__(self, *args, **kwargs):
self.__args = args
self.__kwargs = kwargs
def __iter__(self):
return gen_func(*self.__args, **self.__kwargs)
return _multigen
@multigen
def myxrange(n):
i = 0
while i < n:
yield i
i += 1
m = myxrange(5)
print list(m)
print list(m)
Run Code Online (Sandbox Code Playgroud)
Mat*_*t S 11
使用 itertools 非常简单。
import itertools
alist = [1,2,3]
repeatingGenerator = itertools.cycle(alist)
print(next(generatorInstance)) #=> yields 1
print(next(generatorInstance)) #=> yields 2
print(next(generatorInstance)) #=> yields 3
print(next(generatorInstance)) #=> yields 1 again!
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
9960 次 |
| 最近记录: |