python 如何将函数和参数放入python队列?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/683542/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 20:37:32  来源:igfitidea点击:

how to put a function and arguments into python queue?

pythonmultithreading

提问by grigoryvp

I have a python program with 2 threads ( let's name them 'source' and 'destination' ). Source thread sometimes post a message to destination thread with some arguments. Than destination thread picks a message it must call a corresponding function with aruments saved in message.

我有一个带有 2 个线程的 python 程序(让我们将它们命名为 'source' 和 'destination' )。源线程有时会使用一些参数将消息发布到目标线程。比目标线程选择一条消息,它必须调用相应的函数,并将参数保存在消息中。

This task can be solved multiple ways. The easy one is tu put a big 'if...if..if' in destination thread's message pick cycle and call function according to received message type and saved arguments. But this will result in huge amounf of code ( or big lookup table ) and adding new messages / handler function will evolve additonal step to write code in message pick cycle.

这个任务可以通过多种方式解决。最简单的方法是根据接收到的消息类型和保存的参数在目标线程的消息选择周期和调用函数中放置一个大的“if...if...if”。但这将导致大量代码(或大查找表),并且添加新消息/处理程序函数将演变为在消息选择周期中编写代码的附加步骤。

Since python treats functions as first-class objects and have tuples, i want to put a function and argumens inside a message, so than destination thread picks a message it just call a functon saved within a message without any knowledge what function it is.

由于python将函数视为一流对象并具有元组,因此我想在消息中放置一个函数和参数,因此比目标线程选择一条消息,它只是调用保存在消息中的函数,而不知道它是什么函数。

I can write a code for a functions with specified number of arguments:

我可以为具有指定数量参数的函数编写代码:

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"

The question is: how to modify a code so i can put() a function with any number of arguments in queue? for example HandleAnotherMsg() ? Using q.put( (HandleAnotherMsg, 1, 2, 3) ) will rise a compilation error :(

问题是:如何修改代码以便我可以将具有任意数量参数的函数放入队列中?例如 HandleAnotherMsg() ?使用 q.put( (HandleAnotherMsg, 1, 2, 3) ) 将引发编译错误:(

回答by theller

So simple:

很简单:

def DestinationThread( a ) :
  while True :
    items = q.get()
    func = items[0]
    args = items[1:]
    func(*args)

回答by cthulahoops

Another interesting option is simply to pass in a lambda.

另一个有趣的选择是简单地传入一个 lambda。

q.put(lambda: HandleMsg(1,2))
q.put(lambda: HandleAnother(8, "hello", extra="foo"))

def DestinationThread() :
   while True :
      f = q.get()
      f()

回答by Toni Ru?a

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"

回答by Jorenko

I've used a similar construct before:

我以前使用过类似的构造:

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

You should then be able to pass x to your other thread and call it from there:

然后您应该能够将 x 传递给您的另一个线程并从那里调用它:

x() # returns the same as zip([0,1], [2,3], [4,5])

回答by Ber

You can create an abstract message class with a run method. Then for each function that need to be transmitted via the queue, subclass and implement the function as the run method. The sending thread will create an instance of the proper sub class and put it into the queue. The receiving thread will get an object from the queue and blindly execute the run method.

您可以使用 run 方法创建抽象消息类。然后对于每个需要通过队列传输的函数,将函数子类化并实现为run方法。发送线程将创建适当子类的实例并将其放入队列中。接收线程会从队列中获取一个对象并盲目执行run方法。

This is usually called the Command pattern (Gamma et al.)

这通常称为命令模式(Gamma 等人)

Example:

例子:

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

The sender will instantiate and send a message:

发件人将实例化并发送一条消息:

queue.put(MessageOne(one='Eins', two='Deux'))

The receiver simply gets a message object and execute it run method (without having to it..else.. thru the available types of messages):

接收者只需获取一个消息对象并执行它的 run 方法(无需通过可用类型的消息):

msg = queue.get()
msg.run()

回答by Ber

It sounds like you want to use the apply()intrinsic or its successor:

听起来您想使用apply()内在或其后继者:

def f(x. y):
   print x+y

args = ( 1, 2 )

apply(f, args)   # old way

f(*args)        # new way

回答by Geo

Why don't you subclass Queue?

为什么不将 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)

or, why don't you put a list?

或者,你为什么不列出一个清单?


list = [function_obj]
for arg in function_args:
   list.append(arg)
queue.put(list)