2009-03-25 6 views
10

Tengo un programa python con 2 hilos (llamémosles 'fuente' y 'destino'). El hilo de origen a veces publica un mensaje al hilo de destino con algunos argumentos. Después de que el hilo de destino selecciona un mensaje, debe llamar a una función correspondiente con los argumentos guardados en el mensaje.cómo poner una función y argumentos en la cola de python?

Esta tarea se puede resolver de varias maneras. El más fácil es poner un gran 'if ... if..if' en el ciclo de selección de mensajes del hilo de destino y llamar a la función según el tipo de mensaje recibido y los argumentos guardados. Pero este dará como resultado una enorme cantidad de código (o una gran tabla de búsqueda) y al agregar nuevos la función de manejo de mensajes/controlador evolucionará paso adicional para escribir código en el ciclo de selección de mensaje .

Dado que las funciones trata Python como objetos de primera clase y tienen tuplas, quiero poner una función y argumens dentro de un mensaje, por lo que el hilo de destino recoge un mensaje que acaba de llamar a un functon guardado dentro de un mensaje sin ningún conocimiento qué función es.

puedo escribir un código para una función con el número especificado de argumentos:

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" 

La pregunta es: cómo modificar un código para que pueda poner() una función con cualquier número de argumentos en la cola ? por ejemplo, HandleAnotherMsg()? Usando q.put ((HandleAnotherMsg, 1, 2, 3)) se levantará un error de compilación :(

+0

¿Puede publicar el error que está obteniendo? –

Respuesta

24

tan simple:?

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

¿Por qué no subclase cola?


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) 

o, ¿por qué no pones una lista


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

¿Alguien habría preguntado por qué? –

+0

No responde la pregunta. Cada elemento en la cola necesita codificar una función y un número desconocido de argumentos. No es útil presionar cada argumento como un valor separado en la cola. – cthulahoops

+0

En realidad, el segundo fragmento de código es relevante, aunque los anteriores son más útiles. – cthulahoops

8
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" 
0

Parece que usted quiere utilizar el apply() intrínseca o su sucesor:

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

args = (1, 2) 

apply(f, args) # old way 

f(*args)  # new way 
2

He usado una construcción similar antes:

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

A continuación, debería ser capaz de pasar x para el otro hilo y llamar desde allí:

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

Puede crear una clase de mensaje abstracto con un método de ejecución. Luego, para cada función que necesita transmitirse a través de la cola, subclase e implementar la función como el método de ejecución. El hilo de envío creará una instancia de la subclase adecuada y la colocará en la cola. El hilo de recepción obtendrá un objeto de la cola y ejecutará a ciegas el método de ejecución.

Esto generalmente se llama patrón de comando (Gamma et al.)

Ejemplo:

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 

El remitente instanciar y enviar un mensaje:

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

El receptor simplemente se pone un objeto de mensaje y ejecutarlo método run (sin tener que it..else .. a través de los tipos de mensajes disponibles):

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

Otra opción interesante es simpl y pasar en una lambda.

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

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