简体   繁体   English

如何判断发电机是否刚启动?

[英]How can I tell whether a generator was just-started?

I'd like a function, is_just_started , which behaves like the following: 我想要一个函数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

How can I implement this function? 我该如何实现这个功能?

I looked at the .gi_running attribute but it appears to be used for something else. 我查看了.gi_running属性,但它似乎用于其他东西。

If I know the first value that needs to be sent into the generator, I can do something like this: 如果我知道需要发送到生成器的第一个值,我可以这样做:

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

However, this seems abhorrent. 然而,这似乎令人憎恶。

This only works in Python 3.2+: 这仅适用于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'

So, the requested function is: 因此,请求的功能是:

import inspect

def is_just_started(gen):
    return inspect.getgeneratorstate(gen) == inspect.GEN_CREATED:

Out of curiosity, I looked into CPython to figure out how it was determining this... Apparently it looks at generator.gi_frame.f_lasti which is the "index of last attempted instruction in bytecode". 出于好奇,我调查了CPython以弄清楚它是如何确定的......显然它看着generator.gi_frame.f_lasti ,它是“字节码中最后一次尝试指令的索引”。 If it's -1 then it hasn't started yet. 如果它是-1那么它还没有开始。

Here's a py2 version: 这是一个py2版本:

def is_just_started(gen):
    return gen.gi_frame is not None and gen.gi_frame.f_lasti == -1

Make a new generator which simply yields from your generator of interest. 制造一台新的发电机,只需从您感兴趣的发电机中产生。 It sets a flag once the first value has been consumed . 一旦消耗了第一个值,它就会设置一个标志 Afterwards, it can simply use yield from for the rest of the items. 之后,它可以简单地使用其他项目的yield from

Use the substitute generator as a drop in replacement for the generator you're interested in monitoring the "is_just_started" state. 使用替代生成器代替您有兴趣监视“is_just_started”状态的生成器。

This technique is non-intrusive, and can be used even on generators for which you have no control over the source code. 此技术是非侵入式的,甚至可以在您无法控制源代码的生成器上使用。

You may create a iterator and set the flag as the instance property to iterator class as: 您可以创建一个迭代器并将标志作为实例属性设置为迭代器类,如下所示:

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()

And your value check function would be like: 你的价值检查功能如下:

def is_just_started(my_generator):
    return my_generator.is_just_started

Sample run: 样品运行:

>>> 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

To know the difference between iterator and generator , check Difference between Python's Generators and Iterators 要了解迭代器生成器之间的区别,请检查Python的生成器和迭代器之间的差异

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM