関数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
しかし、これは忌まわしいようです。
これは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
これは、「バイトコードで最後に試行された命令のインデックス」です。もし -1
その後、まだ開始されていません。
ここにpy2バージョンがあります:
def is_just_started(gen):
return gen.gi_frame is not None and gen.gi_frame.f_lasti == -1
目的のジェネレーターから単純に生成される新しいジェネレーターを作成します。 最初の値が消費されるとフラグが設定されます。その後、残りのアイテムにyield from
を使用できます。
「is_just_started」状態の監視に関心のあるジェネレーターの代わりに、代替のジェネレーターを使用します。
この手法は非侵入型であり、ソースコードを制御できないジェネレーターでも使用できます。
イテレータを作成し、インスタンスプロパティとしてフラグを次のようにイテレータクラスに設定できます。
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の違いを知るには、- Pythonのジェネレータとイテレータの違い