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

I am trying to define the generator function mycount() , which can be reset with the send(0) generator function, as in the example below. Everything works fine, except when I use send(0) for a new generator object that is not already running. In this case, it gives a TypeError . Is there any function that checks if the generator started, or do I need to catch a TypeError and create a new generator object in this case with mycount(0) ?

 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 
+6
python generator
Jul 16 '13 at 19:03
source share
4 answers

In order not to send a non- None value to the generator with start enabled, first call next or send(None) . I agree with the rest that David Beazley coroutine decorator (in python 3.x you need to call the __next__() function instead of next() ) is a great option. Although this decorator is simple, I have also successfully used the copipes library, which is a good implementation of many of the utilities from Beazley's presentation, including coroutines.

Regarding whether the generator can be checked to start - in Python 3 you can use inspect.getgeneratorstate . This is not available in Python 2, but the CPython implementation is pure python and does not rely on anything new for Python 3, so you can test 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 

In particular, g2 starts if inspect.getgeneratorstate(g2) != inspect.GEN_CREATED .

+7
Jul 18 '13 at 1:05
source share

As follows from your error, the send function must be called using None on a generator with start-up enabled (docs-link) .

You can catch a TypeError and throw from there:

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

In any case, it cannot be used for the "reset" generator, it just needs to be redone.

An excellent overview of generator concepts and syntax here , covering a chain of generators and other advanced topics.

+1
Jul 17 '13 at 15:38
source share

In particular, you can find a way to use the consumer decorator described on page I-131 of David Basley's โ€œTricks of the Generatorโ€, to which J. Gwyn provided a link:

 def consumer(func): def start(*args,**kwargs): c = func(*args,**kwargs) c.next() return c return start 

I use something similar in my code.

Please note that if v is None preferable if v == None .

+1
Jul 17 '13 at 17:55
source share

Here's the full implementation of the Python2 compatible procedure, getgeneratorstate (gtor), with test code.

 import unittest import enum class GtorState(enum.Enum): GEN_RUNNING ='GEN_RUNNING' GEN_CLOSED ='GEN_CLOSED' GEN_CREATED ='GEN_CREATED' GEN_SUSPENDED ='GEN_SUSPENDED' @staticmethod def getgeneratorstate(gtor): if gtor.gi_running: return GtorState.GEN_RUNNING if gtor.gi_frame is None: return GtorState.GEN_CLOSED if gtor.gi_frame.f_lasti == -1: return GtorState.GEN_CREATED return GtorState.GEN_SUSPENDED #end-def def coro000(): """ a coroutine that does little """ print('-> coroutine started') x =yield print('-> coroutine received ', x) class Test_Coro(unittest.TestCase): def test_coro000(self): my_coro000 =coro000() self.assertEqual( GtorState.getgeneratorstate(my_coro000), GtorState.GEN_CREATED) next(my_coro000) # prints '-> coroutine started' self.assertEqual( GtorState.getgeneratorstate(my_coro000), GtorState.GEN_SUSPENDED) try: my_coro000.send(42) # prints '-> coroutine received 42 self.assertEqual( GtorState.getgeneratorstate(my_coro000), GtorState.GEN_SUSPENDED) self.fail('should have raised StopIteration ') except StopIteration: self.assertTrue(True, 'On exit a coroutine will throw StopIteration') self.assertEqual( GtorState.getgeneratorstate(my_coro000), GtorState.GEN_CLOSED) 
0
Oct 25 '17 at 10:15
source share



All Articles