【问题标题】:How to use a decorator with a coroutine in Python?如何在 Python 中使用带有协程的装饰器?
【发布时间】:2018-06-30 11:53:32
【问题描述】:

我正在尝试制作一个程序,该程序会产生两个相互通信的进程。我已经阅读了关于协程的内容,并认为这次采用它会很好,并且由于协程在使用之前需要准备好,所以我认为最好让装饰器自动执行此操作。

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 方法(rec)将其绑定到msg 并与当前时间一起打印出来。

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

self.coroutine.send( self.pipe.recv() )
AttributeError: 'function' object has no attribute 'send'

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

【问题讨论】:

    标签: python python-decorators coroutine


    【解决方案1】:

    你忘记调用协程了:

    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 )
    

    【讨论】:

    • 哦,非常感谢您的回答!我认为装饰器中的cr = func(*args, **kwargs) 已经可以完成这项工作了。在循环之前不调用它,是否可以仅将其用作self.coroutine.send(),也许使用装饰器?
    • 请记住,cr = func(*args, **kwargs) 仅在您调用该函数时被调用。我给了你 2 个例子,包括一个不同的 cr 用于类和实例
    • @maynull 不客气!如果您还有什么想问的,欢迎您在 cmets 上发帖或作为 stackoverflow 上的新问题。我强烈建议阅读有关生成器的信息以供将来编程。也祝你有美好的一天:-)
    猜你喜欢
    • 2019-11-24
    • 2020-09-05
    • 1970-01-01
    • 2014-02-16
    • 2015-01-15
    • 2014-07-21
    • 2016-09-05
    • 2012-12-23
    • 2011-05-28
    相关资源
    最近更新 更多