如何在 Python 中使用带有协程的装饰器?
How to use a decorator with a coroutine in Python?
我正在尝试编写一个程序来生成两个相互通信的进程。我已经阅读了有关协程的信息,并认为这次采用它会很好,并且由于协程需要在使用前启动,所以我认为让装饰器自动执行此操作会很好。
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'
我假设装饰协程有问题,但我不知道问题到底是什么以及如何解决它。我想得到一些帮助。
您忘记调用协程了:
def run(self):
# Create and initialize the coroutine
cr = self.coroutine()
while True:
# Send the data
cr.send( self.pipe.recv() )
如果你希望它被class绑定,就是这样
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 )
我正在尝试编写一个程序来生成两个相互通信的进程。我已经阅读了有关协程的信息,并认为这次采用它会很好,并且由于协程需要在使用前启动,所以我认为让装饰器自动执行此操作会很好。
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'
我假设装饰协程有问题,但我不知道问题到底是什么以及如何解决它。我想得到一些帮助。
您忘记调用协程了:
def run(self):
# Create and initialize the coroutine
cr = self.coroutine()
while True:
# Send the data
cr.send( self.pipe.recv() )
如果你希望它被class绑定,就是这样
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 )