簡體   English   中英

如何判斷發電機是否剛啟動?

[英]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

然而,這似乎令人憎惡。

這僅適用於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

要了解迭代器生成器之間的區別,請檢查Python的生成器和迭代器之間的差異

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM