我怎么知道一台发电机是否刚起步?
我想要一个函数, is_just_started
,其行为如下:
>>> def gen(): yield 0; yield 1 >>> a = gen() >>> is_just_started(a) True >>> next(a) 0 >>> is_just_started(a) False >>> next(a) 1 >>> is_just_started(a) False >>> next(a) Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration >>> is_just_started(a) False
我怎样才能实现这个function?
我看着.gi_running
属性,但似乎用于其他的东西。
如果我知道需要发送到生成器的第一个值,我可以这样做:
def safe_send(gen, a): try: return gen.send(a) except TypeError as e: if "just-started" in e.args[0]: gen.send(None) return gen.send(a) else: raise
但是,这似乎是可恶的。
这只适用于Python 3.2+:
>>> def gen(): yield 0; yield 1 ... >>> a = gen() >>> import inspect >>> inspect.getgeneratorstate(a) 'GEN_CREATED' >>> next(a) 0 >>> inspect.getgeneratorstate(a) 'GEN_SUSPENDED' >>> next(a) 1 >>> inspect.getgeneratorstate(a) 'GEN_SUSPENDED' >>> next(a) Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration >>> inspect.getgeneratorstate(a) 'GEN_CLOSED'
所以,要求的function是:
import inspect def is_just_started(gen): return inspect.getgeneratorstate(gen) == inspect.GEN_CREATED:
出于好奇,我查看了CPython,看看它是如何确定的…显然它看起来是generator.gi_frame.f_lasti
,它是“字节码中最后尝试指令的索引”。 如果它是-1
那么它还没有开始。
这是一个py2版本:
def is_just_started(gen): return gen.gi_frame is not None and gen.gi_frame.f_lasti == -1
做一个新的发电机,只需从您感兴趣的发电机产生。 一旦第一个值被消耗,它就会设置一个标志 。 之后,它可以简单地使用yield from
其他项目的yield from
。
使用替代发生器作为您感兴趣的监测“is_just_started”状态的发电机的替代品。
这种技术是非侵入式的,甚至可以用在你无法控制源代码的发生器上。
您可以创build一个迭代器,并将该标志设置为迭代器类的实例属性:
class gen(object): def __init__(self, n): self.n = n self.num, self.nums = 0, [] self.is_just_started = True # Your flag def __iter__(self): return self # Python 3 compatibility def __next__(self): return self.next() def next(self): self.is_just_started = False # Reset flag with next if self.num < self.n: cur, self.num = self.num, self.num+1 return cur else: raise StopIteration()
而你的价值检查function将如下所示:
def is_just_started(my_generator): return my_generator.is_just_started
样品运行:
>>> a = gen(2) >>> is_just_started(a) True >>> next(a) 0 >>> is_just_started(a) False >>> next(a) 1 >>> is_just_started(a) False >>> next(a) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 19, in next StopIteration
要知道迭代器和生成器之间的区别,请检查Python的生成器和迭代器之间的差异