如何判断发电机是否刚刚启动?
How can I tell whether a generator was just-started?
我想要一个函数,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
如何实现这个功能?
我查看了 .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
然而,这似乎令人厌恶。
您可以创建一个迭代器并将标志设置为实例 属性 到迭代器 class 为:
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()
你的值检查函数将是这样的:
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
要了解 iterator 和 generator 之间的区别,请检查 Difference between Python's Generators and Iterators
制作一个新的发电机,它只是从您感兴趣的发电机中产生。 一旦第一个值被消耗,它就会设置一个标志。之后,它可以简单地对其余项目使用 yield from
。
使用替代发电机替代您有兴趣监控 "is_just_started" 状态的发电机。
这种技术是非侵入式的,甚至可以用于您无法控制其源代码的生成器。
这仅适用于 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'
因此,请求的函数是:
import inspect
def is_just_started(gen):
return inspect.getgeneratorstate(gen) == inspect.GEN_CREATED:
出于好奇,我查看了 CPython 以弄清楚它是如何确定的...显然它查看的是 generator.gi_frame.f_lasti
,即 "index of last attempted instruction in bytecode"。如果是 -1
则表示尚未开始。
这是一个py2版本:
def is_just_started(gen):
return gen.gi_frame is not None and gen.gi_frame.f_lasti == -1
我想要一个函数,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
如何实现这个功能?
我查看了 .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
然而,这似乎令人厌恶。
您可以创建一个迭代器并将标志设置为实例 属性 到迭代器 class 为:
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()
你的值检查函数将是这样的:
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
要了解 iterator 和 generator 之间的区别,请检查 Difference between Python's Generators and Iterators
制作一个新的发电机,它只是从您感兴趣的发电机中产生。 一旦第一个值被消耗,它就会设置一个标志。之后,它可以简单地对其余项目使用 yield from
。
使用替代发电机替代您有兴趣监控 "is_just_started" 状态的发电机。
这种技术是非侵入式的,甚至可以用于您无法控制其源代码的生成器。
这仅适用于 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'
因此,请求的函数是:
import inspect
def is_just_started(gen):
return inspect.getgeneratorstate(gen) == inspect.GEN_CREATED:
出于好奇,我查看了 CPython 以弄清楚它是如何确定的...显然它查看的是 generator.gi_frame.f_lasti
,即 "index of last attempted instruction in bytecode"。如果是 -1
则表示尚未开始。
这是一个py2版本:
def is_just_started(gen):
return gen.gi_frame is not None and gen.gi_frame.f_lasti == -1