1

Is there a coroutine decorator that is built into python? I've seen something like that in tornado, but is there something in python that looks like this?

@coroutine
def func():
    while True:
        val = yield

So that I can call it and send to it immediately without using next first. I suppose a basic approach would be:

def coroutine(func):
    @functools.wraps(func)
    def wrapper_coroutine(*args, **kwargs):
        f = func(*args, **kwargs)
        next(f)
        return f
    return wrapper_coroutine

But I'm wondering if python has this built-in somewhere I'm missing.

David542
  • 104,438
  • 178
  • 489
  • 842
  • `coroutine` is not built-in name. I think you saw this: https://github.com/tornadoweb/tornado/blob/d6819307ee050bbd8ec5deb623e9150ce2220ef9/tornado/gen.py#L156. – Boseong Choi Mar 07 '20 at 02:48
  • The answer to this seems to be no, there is no such thing in the standard library. – kaya3 Mar 07 '20 at 02:56

1 Answers1

3

You have probably answered this for yourself already, but for the benefit of anyone else that comes across this question, I was looking for the same thing and found the following:

The simple answer, as stated in the comments is; there appears to be no such thing in the standard library.

Answers on the subject of coroutines and their application on this site point to an implementation of a @coroutine decorator by David Beazely, a code snippet from which is listed below for convenience.

def coroutine(func):
    def start(*args,**kwargs):
        cr = func(*args,**kwargs)
        cr.next()
        return cr
    return start

In reply to @DocDriven's comment; the above is a direct copy of David Beazely's implementation, which will work with versions of Python prior to v3.2. The accepted answers to this question gives a fuller explanation and discussion, but from Python v3.2 .next() has been replaced by the built in free function next(). So when using version 3.2 of Python and later the call to cr.next() is replaced with the call to the free function next(cr).

Updating David Beazely's original implementation to work with Python versions 3.2 and later, the full code with example use becomes:

def coroutine(func):
    def start(*args,**kwargs):
        cr = func(*args,**kwargs)
        next(cr)
        return cr
    return start

# Example use
if __name__ == '__main__':
    @coroutine
    def grep(pattern):
        print("Looking for %s" % pattern)
        while True:
            line = (yield)
            if pattern in line:
                print(line)

    g = grep("python")
    # Notice how you don't need a next() call here
    g.send("Yeah, but no, but yeah, but no")
    g.send("A series of tubes for pythons")
    g.send("python generators rock!")

This worked for me with Python v3.7.3

Hargrovm
  • 1,053
  • 8
  • 10
  • Shouldn't ``cr.next()`` be ``next(cr)``? This line gives me an ``AttributeError: 'generator' object has no attribute 'next'`` – DocDriven Aug 08 '21 at 02:14