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

前端 未结 4 409
轻奢々
轻奢々 2021-01-05 00:46

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

相关标签:
4条回答
  • 2021-01-05 01:07

    Here's a complete implementation Python2 compatible routine, 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 讨论(0)
  • 2021-01-05 01:14

    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.

    0 讨论(0)
  • 2021-01-05 01:16

    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.

    0 讨论(0)
  • 2021-01-05 01:30

    In particular, you might find a way to use the consumer decorator described on p. I-131 of David Beazley's "Generator Tricks," 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.

    Note that if v is None is preferred over if v == None.

    0 讨论(0)
提交回复
热议问题