我怎么知道一台发电机是否刚起步?

我想要一个函数, 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的生成器和迭代器之间的差异