我有一个包含2个线程的python程序(让我们将它们命名为'source'和 '目的地')。源线程有时会将消息发布到目标 带有一些参数的线程。比目标线程选择一条消息吧 必须使用保存在消息中的历史记录调用相应的函数。
此任务可以通过多种方式解决。容易的就是把它放得很大 'if ... if..if'在目标线程的消息中选择循环并调用 根据收到的消息类型和保存的参数进行功能。但是这个 将导致巨大的代码(或大查找表)和添加新的 消息/处理函数将演变为编写代码的附加步骤 消息选择周期。
因为python将函数视为第一类对象并且有元组,所以我想要 将一个函数和argumens放在一个消息中,所以比目标线程 选择一条消息,它只是在没有任何消息的情况下调用保存在消息中的功能 知道它是什么功能。
我可以为具有指定数量的参数的函数编写代码:
from Queue import *
from thread import *
from time import *
q = Queue()
def HandleMsg( arg1, arg2 ) :
print arg1, arg2
def HandleAnotherMsg( arg1, arg2, arg3 ) :
print arg1, arg2, arg3
def DestinationThread( a ) :
while True :
(f, a, b) = q.get()
f( a, b )
start_new_thread( DestinationThread, ( 0, ) )
print "start"
sleep( 1 )
q.put( (HandleMsg, 1, 2) )
sleep( 1 )
print "stop"
问题是:如何修改代码,以便我可以将()函数放入 队列中的任意数量的参数?例如HandleAnotherMsg()? 使用q.put((HandleAnotherMsg,1,2,3))将引发编译错误:(
答案 0 :(得分:27)
这么简单:
def DestinationThread( a ) :
while True :
items = q.get()
func = items[0]
args = items[1:]
func(*args)
答案 1 :(得分:12)
另一个有趣的选择就是传入一个lambda。
q.put(lambda: HandleMsg(1,2))
q.put(lambda: HandleAnother(8, "hello", extra="foo"))
def DestinationThread() :
while True :
f = q.get()
f()
答案 2 :(得分:9)
from Queue import *
from thread import *
from time import *
q = Queue()
def HandleMsg( arg1, arg2 ) :
print arg1, arg2
def HandleAnotherMsg( arg1, arg2, arg3 ) :
print arg1, arg2, arg3
def DestinationThread() :
while True :
f, args = q.get()
f(*args)
start_new_thread( DestinationThread, tuple() )
print "start"
sleep( 1 )
q.put( (HandleMsg, [1, 2]) )
sleep( 1 )
q.put( (HandleAnotherMsg, [1, 2, 3]) )
sleep( 1 )
print "stop"
答案 3 :(得分:2)
我之前使用过类似的结构:
class Call:
def __init__(self, fn, *args, **kwargs):
self.fn = fn
self.args = args
self.kwargs = kwargs
def __call__(self):
return self.fn(*self.args, **self.kwargs)
x = Call(zip, [0,1], [2,3], [4,5])
然后你应该能够将x传递给你的另一个线程并从那里调用它:
x() # returns the same as zip([0,1], [2,3], [4,5])
答案 4 :(得分:0)
听起来你想要使用apply()
内在函数或其后继者:
def f(x. y):
print x+y
args = ( 1, 2 )
apply(f, args) # old way
f(*args) # new way
答案 5 :(得分:0)
您可以使用run方法创建抽象消息类。然后对于需要通过队列传输的每个函数,子类并将该函数实现为run方法。 发送线程将创建正确子类的实例并将其放入队列中。接收线程将从队列中获取一个对象并盲目地执行run方法。
这通常称为命令模式(Gamma等人)
示例:
class Message (object):
"""abstract message class"""
def __init__(self, **kwargs):
self.kwargs = kwargs
def run(self):
pass
class MessageOne (Message):
"""one message class"""
def run(self):
# perform this emssage's action using the kwargs
发件人将实例化并发送消息:
queue.put(MessageOne(one='Eins', two='Deux'))
接收者只需获取一个消息对象并执行它运行方法(无需通过可用的消息类型...)
msg = queue.get()
msg.run()
答案 6 :(得分:-2)
为什么不将Queue子类化?
class MyQueue(Queue):
# by using *args, you can have a variable number of arguments
def put(self,*args):
for arg in args:
Queue.put(self,arg)
或者,你为什么不列出名单?
list = [function_obj]
for arg in function_args:
list.append(arg)
queue.put(list)