我所追求的是一种确定发电机是否“正在运行”的方法。
我对“当前正在运行”的定义是:
next
或.send(None)
或其他一些迭代操作,例如for循环,先前已在生成器上执行,AND .throw(some_error)
被捕获并且不会耗尽生成器,因为一些新循环已启动;没有循环或yield from
处理过的错误通常会耗尽发电机。)我知道没有办法(或者至少是一种简单的方法)在生成器中“窥视”并找出它是否会在下一次迭代中引发StopIteration
。这与发电机的性质是对立的,并且 NOT 是我追求的。
假设我有一些生成器,g
由某个生成器函数f
创建:
def f():
'''Lots of 1s.'''
print('I am now running.')
while True:
try:
signal = yield 1
if signal:
break
except GeneratorExit:
raise # important so that closing the generator doesn't cause a RuntimeError
except Exception:
print('caught exception!')
我们可以通过这种方式“初始化”生成器:
>>> g = f()
>>> next(g)
I am now running.
1
# OR:
>>> g.send(None) # equivalent to next(g)
I am now running.
1
如果我将任何真相发送到生成器,则会引发StopIteration
错误(例如g.send('foo')
)。或者,如果我拨打g.close()
,然后执行next(g)
,我也会获得StopIteration
。如果我向g.throw(e)
抛出任何错误,则生成器将继续。这一切都符合预期。
我希望能够做的是以下内容,它显示此生成器是否正在运行:
>>> g=f()
>>> g.running
False
>>> g.send(None)
I am now running.
1
>>> g.running
True
>>> g.close()
>>> g.running
False
我在答案中提供了一种可能的方法。但是,我认为必须有更好的方法。
答案 0 :(得分:5)
inspect.getgeneratorstate
告诉您发电机的状态:
>>> import inspect
...
... def gen():
... yield 1
...
... g = gen()
...
>>> inspect.getgeneratorstate(g)
'GEN_CREATED'
>>> next(g)
1
>>> inspect.getgeneratorstate(g)
'GEN_SUSPENDED'
>>> next(g)
>>> inspect.getgeneratorstate(g)
'GEN_CLOSED'
答案 1 :(得分:0)
我唯一的想法是某种生成器包装器,其方法可以委托给存储的生成器,但这有点笨拙。它可能看起来像这样(没有经过测试):
class MyGen():
'''Generator wrapper with 'exhausted' and 'running' flags.'''
def __new__(cls, some_func):
cls._func = some_func
return super().__new__(cls)
def __call__(self, *args, **kwargs):
self.exhausted = False
self.running = False
self.start(*args, **kwargs)
return self
def start(self, *args, **kwargs):
self._gen = self._func(*args, **kwargs)
def __next__(self):
try:
self.running = True
next(self._gen)
except StopIteration:
self.exhausted = True
self.running = False
raise
def send(self, *args, **kwargs):
try:
self.running = True
self._gen.send(*args, **kwargs)
except StopIteration:
self.exhausted = True
self.running = False
raise
def throw(self, *args, **kwargs):
try:
self._gen.throw(*args, **kwargs)
except StopIteration:
self.exhausted = True
self.running = False
raise
def close(self):
self._gen.close()
self.exhausted = True
self.running = False
您甚至可以将其用作装饰者:
@MyGen
def f():
yield 1
我真的不喜欢这样,因为看起来真的应该有一个现有的地方来寻找一个耗尽的发电机"或"发电机运行"旗。