Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a Python function that checks if a generator is started?

I try to define a generator function mycount() that can be reset with the generator function send(0) as in the example below. Everything works fine, except when I use send(0) on a new generator object that hasn't started yet. In this case it gives a TypeError. Is there any function that checks if the generator has started or do I have to catch the TypeError and create a new generator object with mycount(0) in such case?

def mycount(value):
    while True:
        v = yield value
        if v == None:
            value = value + 1
        else:
            value = v

g = mycount(3)
print(next(g))    # prints 3
print(next(g))    # prints 4
print(g.send(0))  # prints 0
print(next(g))    # prints 1
print(next(g))    # prints 2

g2 = mycount(3)
g2.send(0)
# TypeError: can't send non-None value to a just-started generator
like image 338
Holger Avatar asked Jul 16 '13 19:07

Holger


People also ask

How do you check if it is a generator Python?

from types import GeneratorType;type(myobject, GeneratorType) will give you the proper result for objects of class 'generator'.

How does Python know if a function is a generator?

Create Generators in PythonIf a function contains at least one yield statement (it may contain other yield or return statements), it becomes a generator function. Both yield and return will return some value from a function.

Which keyword tell the Python that function is generator?

It is quite simple to create a generator in Python. It is similar to the normal function defined by the def keyword and uses a yield keyword instead of return. Or we can say that if the body of any function contains a yield statement, it automatically becomes a generator function.

What does next () do in a generator Python?

The next() function returns the next item in an iterator. You can add a default return value, to return if the iterable has reached to its end.


2 Answers

To avoid sending a non-None value to a just-started generator, you need to call next or send(None) first. I agree with the others that David Beazley's coroutine decorator (in python 3.x you need to call to __next__() function instead of next()) is a great option. Though that particular decorator is simple, I've also successfully used the copipes library, which is a nice implementation of many of the utilities from Beazley's presentations, including coroutine.

Regarding whether one can check if a generator is started - in Python 3, you can use inspect.getgeneratorstate. This isn't available in Python 2, but the CPython implementation is pure python and doesn't rely on anything new to Python 3, so you can check yourself in the same way:

if generator.gi_running:
    return GEN_RUNNING
if generator.gi_frame is None:
    return GEN_CLOSED
if generator.gi_frame.f_lasti == -1:
    return GEN_CREATED
return GEN_SUSPENDED

Specifically, g2 is started if inspect.getgeneratorstate(g2) != inspect.GEN_CREATED.

like image 114
Rich Frank Avatar answered Sep 28 '22 01:09

Rich Frank


As your error implies the send function must be called with None on a just-started generator (docs-link).

You could catch the TypeError and roll from there:

    #...
    try:
        g2.send(0)
    except TypeError:
        #Now you know it hasn't started, etc.
        g2.send(None)

Either way it can't be used to 'reset' the generator, it just has to be remade.

Great overview of generator concepts and syntax here, covering chaining of generators and other advanced topics.

like image 42
Jake Gwyn Avatar answered Sep 27 '22 23:09

Jake Gwyn