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

时间:2018-06-30 11:53:32

标签: python python-decorators coroutine

我正在尝试制作一个程序,该程序产生两个相互通信的进程。我已经读过有关协程的信息,并认为这一次采用它会是一件好事,并且由于协程需要在使用前进行上底漆,所以我认为让装饰器自动执行此操作会很好。

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()

sen进程每秒发送一个随机整数到rec进程。每当一个整数到达时,coroutine的{​​{1}}方法将其绑定到rec并在当前时间将其打印出来。

我认为代码没有问题,但是显示了错误消息:

msg

我认为装饰协程时存在问题,但我不知道到底是什么问题以及如何解决。我想获得一些帮助。

1 个答案:

答案 0 :(得分:5)

您忘记给协程打电话了:

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

    while True:
        # Send the data
        cr.send( self.pipe.recv() )

如果您希望它受类约束,那就是这种方式

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


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

这是实例绑定的方式。

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 )