如何在Python中使用带协同程序的装饰器?

may*_*ull 0 python coroutine python-decorators

我正在尝试制作一个程序,它产生两个互相交流的进程.我已经阅读了关于协同程序的内容,并认为这次采用它会很好,而且由于协程在使用之前需要启动,我认为让装饰器自动完成它会很好.

import multiprocessing as mp
import random
import time
import os
from datetime import datetime, timedelta
from functools import wraps

output, input = mp.Pipe()



def co_deco(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        cr = func(*args, **kwargs)
        cr.send(None)
        return cr
    return wrapper

class sender(mp.Process):
    def __init__(self, pipe):
        mp.Process.__init__(self)
        self.pipe = pipe

    def run(self):
        print('RECEIVER PID: ', os.getpid() )
        while True:
            self.pipe.send( random.randint(0,10) )
            time.sleep(1)

class receiver(mp.Process):
    def __init__(self, pipe):
        mp.Process.__init__(self)
        self.pipe = pipe

    def run(self):
        while True:
            self.coroutine.send( self.pipe.recv() )

    @co_deco
    def coroutine(self):
        while True:
            msg = yield
            print( datetime.now(), msg )



if __name__ == '__main__':
    mp.freeze_support()

    sen = sender(pipe=input)
    rec = receiver(pipe = output)

    sen.start()
    rec.start()
Run Code Online (Sandbox Code Playgroud)

sen进程发送一个随机整数来rec处理每秒.每当一个整数到达时,coroutine方法(of rec)将其绑定并以msg当前时间打印出来.

我发现代码没有问题,但它显示错误消息:

self.coroutine.send( self.pipe.recv() )
AttributeError: 'function' object has no attribute 'send'
Run Code Online (Sandbox Code Playgroud)

我认为装饰协程有一个问题,但我不知道究竟是什么问题,以及如何解决它.我想得到一些帮助.

Bha*_*rel 5

你忘了打电话给coroutine:

def run(self):
    # Create and initialize the coroutine
    cr = self.coroutine()

    while True:
        # Send the data
        cr.send( self.pipe.recv() )
Run Code Online (Sandbox Code Playgroud)

如果你希望它是类绑定的,这就是方法

def co_deco(func):
    cr = func()
    cr.send(None)
    return cr


@co_deco
def coroutine():
    while True:
        msg = yield
        print( datetime.now(), msg )
Run Code Online (Sandbox Code Playgroud)

例如,这就是方式.

def co_deco(func):
    @property
    @wraps(func)
    def wrapper(self, *args, **kwargs):
        try:
            # Get the coroutine from the instance object under a 
            # name with a leading underscore
            return getattr(self, "_" + func.__name__)
        except AttributeError:
            pass

        cr = func(self, *args, **kwargs)
        # Set the coroutine from the instance object under a 
        # name with a leading underscore
        setattr(self, "_" + func.__name__, cr)
        cr.send(None)
        return cr
    return wrapper


@co_deco
def coroutine(self):
    while True:
        msg = yield
        print( datetime.now(), msg )
Run Code Online (Sandbox Code Playgroud)