2009-03-19 7 views
28

Data la Python documentation per Thread.run():python override threading.Thread.run()

You may override this method in a subclass. The standard run() method invokes the callable object passed to the object’s constructor as the target argument, if any, with sequential and keyword arguments taken from the args and kwargs arguments, respectively.

ho costruito il seguente codice:

class DestinationThread(threading.Thread): 
    def run(self, name, config): 
     print 'In thread' 

thread = DestinationThread(args = (destination_name, destination_config)) 
thread.start() 

Ma quando eseguo esso, ricevo il seguente errore :

Exception in thread Thread-1: 
Traceback (most recent call last): 
    File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/threading.py", line 522, in __bootstrap_inner 
    self.run() 
TypeError: run() takes exactly 3 arguments (1 given) 

sembra che mi manca qualcosa di ovvio, ma i vari esempi Ho visto lavorare con questa metodologia. In definitiva sto provando a passare solo la stringa e il dizionario nel thread, se il Costruttore non è la strada giusta, ma piuttosto per creare una nuova funzione per impostare i valori prima di iniziare il thread, sono aperto a quello.

Qualche suggerimento su come realizzare al meglio questo?

risposta

53

In realtà non è necessario suddividere la filettatura. L'unica ragione per cui l'API supporta questo è di renderlo più confortevole per le persone che provengono da Java, dove questo è l'unico modo per farlo in modo sano.

Il modello che si consiglia di utilizzare è passare un metodo al costruttore Thread e chiamare semplicemente .start().

def myfunc(arg1, arg2): 
    print 'In thread' 
    print 'args are', arg1, arg2 

thread = Thread(target=myfunc, args=(destination_name, destination_config)) 
thread.start() 
+5

Questa era un'informazione chiave che mi mancava, ed è per questo che l'ho accettata, ma nel mio caso, in realtà sto estendendo la classe aggiungendo le funzioni necessarie per estrarre i dati dal thread. –

+3

Mille volte sì. Devo spiegare questo molto agli sviluppatori Java. –

+1

Non hai nemmeno bisogno di argomenti = (arg1, arg2). Basta fare target = functools.partial (myfunc, arg1, arg2). – Phob

0

Si definisce il metodo di esecuzione per accettare 3 argomenti, ma lo si chiama con un argomento (Python lo chiama con il riferimento all'oggetto).

È necessario passare gli argomenti da eseguire anziché __init__.

Oppure utilizzare il metodo __init__ per accettare gli argomenti.

+0

Sei sicuro che è di destra? Non pensavo che potessi passare alcun argomento per iniziare(). –

+0

Non puoi, intendevo correre. Grazie. – Vasil

+1

No, questo non funziona. Non è possibile passare argomenti a start() e l'intero punto è che non è possibile chiamare run() direttamente. – cmcginty

4

La documentazione di threading.Thread può sembrare implicare che qualsiasi args posizionali e parole chiave non utilizzati vengono passati a correre. Non sono.

Eventuali args posizionali extra e parola chiave kwargs sono infatti intrappolati dal metodo di default threading.Thread.__init__, ma sono solo passato a un metodo specificato utilizzando target= parola chiave. NON sono passati al metodo run().

Infatti, il Threading documentation a rende chiaro che è il metodo predefinito run() che richiama il target= metodo fornito con gli args intrappolati e kwargs:

"You may override this method in a subclass. The standard run() method invokes the callable object passed to the object’s constructor as the target argument, if any, with sequential and keyword arguments taken from the args and kwargs arguments, respectively."

+0

Sono d'accordo. Alcune delle altre risposte alla domanda originale sbagliano (quelle che mostrano un metodo 'run()' con argomenti in aggiunta a 'self'). –

7

Ecco un esempio di passaggio di argomenti usando threading e non si estende __init__:

import threading 

class Example(threading.Thread): 

    def run(self): 
     print '%s from %s' % (self._Thread__kwargs['example'], 
           self.name) 

example = Example(kwargs={'example': 'Hello World'}) 
example.start() 
example.join() 

ed ecco un esempio utilizzando mutliprocessing:

import multiprocessing 

class Example(multiprocessing.Process): 

    def run(self): 
     print '%s from %s' % (self._kwargs['example'], 
           self.name) 

example = Example(kwargs={'example': 'Hello World'}) 
example.start() 
example.join() 
+10

L'accesso a 'self._Thread__kwargs' è molto brutto. – glglgl

+0

In Python 3, gli attributi di Thread sono stati modificati da privato a protected, ad esempio 'self .__ kwargs' (all'interno della classe Thread) è diventato' self._kwargs'. Ciò consente un accesso leggermente meno brutto, in quanto il nome mangling non viene più utilizzato. Tuttavia, questo cambiamento richiede che uno sia Python versione sensibile se si vuole supportare sia Python 2 sia 3. –

+0

Un altro: non vedo come si possa implementare un metodo 'run()' sovrascritto ** senza ** accedendo direttamente gli attributi Thread '_target',' _args' e '_kwargs' (usando i loro nomi v3): I loro valori devono essere usati (vedi la descrizione di run() che è stata citata in altre risposte), e non hanno accesso metodi. –

0

Se si desidera mantenere il vostro approccio orientato agli oggetti e hanno anche argomenti di esecuzione, è possibile effettuare le seguenti operazioni:

import threading 
class Destination: 
    def run(self, name, config): 
     print 'In thread' 

destination = Destination() 
thread = threading.Thread(target=destination.run, 
    args=(destination_name, destination_config)) 
thread.start() 

Come accennato in precedenza, potrebbe essere fatto anche con partial

from functools import partial 
import threading 
class Destination: 
    def run(self, name, config): 
     print 'In thread' 

destination = Destination() 
thread = threading.Thread(target=partial(
    destination.run, destination_name, destination_config)) 
thread.start() 

Il vantaggio di fare questo rispetto ad un approccio puramente funzionale è che ti consente di mantenere lo stesso altro codice orientato agli oggetti esistente. L'unico cambiamento è quello di avere non sottoclasse Thread, che non dovrebbe essere un grosso problema, dal momento che per threading.Thread documentazione:

only override the init() and run() methods of this class

Se stavate override di filo in modo che si possa accedere all'oggetto filo dall'interno sottoclasse, quindi raccomanderei semplicemente di utilizzare threading.currentThread() dall'interno dell'oggetto. In questo modo si segmento dello spazio dei nomi del thread dal proprio, e per la "Zen di Python" di Tim Peters:

Namespaces are one honking great idea -- let's do more of those!

2

Al fine di affrontare alcune delle confusione sul fatto che un run() metodo ignorato prende argomenti aggiuntivi, qui è un'implementazione di un metodo sovrascritto run() che esegue ciò che il metodo ereditato da threading.Thread.

Nota, questo solo per vedere come si sovrascrive run(); non è pensato per essere un esempio significativo. Se tutto ciò che si vuole fare è invocare una funzione di destinazione con argomenti sequenziali e/o parola chiave, non è necessario avere una sottoclasse; questo è stato indicato ad es. in Jerub's answer a questa domanda.

Il seguente codice supporta sia Python v2 che v3.

Anche se particolare l'accesso ai nomi degli attributi alterati nel codice Python 2 è brutto, io non sono a conoscenza di un altro modo per accedere a questi attributi (fatemi sapere se conoscete uno ...):

import sys 
import threading 

class DestinationThread(threading.Thread): 

    def run(self): 
     if sys.version_info[0] == 2: 
      self._Thread__target(*self._Thread__args, **self._Thread__kwargs) 
     else: # assuming v3 
      self._target(*self._args, **self._kwargs) 

def func(a, k): 
    print("func(): a=%s, k=%s" % (a, k)) 

thread = DestinationThread(target=func, args=(1,), kwargs={"k": 2}) 
thread.start() 
thread.join() 

Esso stampa (testato con Python 2.6, 2.7, 3.4 e su Windows 7):

func(): a=1, k=2