Как использовать декоратор с сопрограммой в Python? - PullRequest
0 голосов
/ 30 июня 2018

Я пытаюсь создать программу, которая порождает два процесса, которые объединяют друг друга. Я читал о сопрограммах и подумал, что было бы хорошо принять его на этот раз, и поскольку сопрограмму нужно подготовить, прежде чем ее использовать, я подумал, что было бы неплохо создать декоратор, который автоматически сделает это.

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'

Я предполагаю, что есть проблема с украшением сопрограммы, но я понятия не имею, в чем конкретно заключается проблема и как ее исправить. Я хотел бы получить помощь с этим.

1 Ответ

0 голосов
/ 30 июня 2018

Вы забыли позвонить сопрограмме:

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