Étant donné la documentation Python pour Thread.run()
:
Vous pouvez remplacer cette méthode dans une sous-classe. La méthode standard run () appelle l’objet appelable transmis au constructeur de l’objet comme argument cible, le cas échéant, avec des arguments séquentiels et des arguments mot-clé extraits des arguments args et kwargs, respectivement.
J'ai construit le code suivant:
class DestinationThread(threading.Thread):
def run(self, name, config):
print 'In thread'
thread = DestinationThread(args = (destination_name, destination_config))
thread.start()
Mais lorsque je l'exécute, je reçois le message d'erreur suivant:
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)
Il semble que je manque quelque chose d’évident, mais les divers exemples que j’ai vus fonctionnent avec cette méthodologie. En fin de compte, j'essaie simplement de passer la chaîne et le dictionnaire dans le thread, si le constructeur n'est pas la bonne manière, mais plutôt de créer une nouvelle fonction pour définir les valeurs avant de démarrer le thread, je suis ouvert à cela.
Des suggestions sur la meilleure façon d'accomplir cela?
Vous n'avez vraiment pas besoin de sous-classer Thread. La seule raison pour laquelle l'API prend en charge cette fonctionnalité est de le rendre plus confortable pour les personnes venant de Java, où c'est le seul moyen de le faire sainement.
Le modèle que nous vous recommandons d’utiliser consiste à transmettre une méthode au constructeur Thread et à appeler simplement .start()
.
def myfunc(arg1, arg2):
print 'In thread'
print 'args are', arg1, arg2
thread = Thread(target=myfunc, args=(destination_name, destination_config))
thread.start()
Voici un exemple de passage d'arguments à l'aide de threading sans extension __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()
Et voici un exemple utilisant multitraitement:
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()
La documentation de threading.Thread
peut sembler impliquer que tous les arguments de position et de mot clé non utilisés sont passés à l'exécution. Ils ne sont pas.
Tous les arguments de position et le mot clé kwargs
supplémentaires sont effectivement interceptés par la méthode threading.Thread.__init__
par défaut, mais ils sont UNIQUEMENT transmis à une méthode spécifiée à l'aide du mot clé target=
. Ils ne sont PAS transmis à la méthode run()
.
En fait, la Documentation de thread) at indique clairement que est la méthode par défaut run()
qui appelle la méthode target=
fournie avec les arguments capturés et kwargs
:
"Vous pouvez remplacer cette méthode dans une sous-classe La méthode standard run () Invoque l’objet appelable passé à Le constructeur de l’objet en tant qu’argument cible arguments de mots-clés extraits des arguments args et kwargs, respectivement. "
Si vous souhaitez conserver votre approche orientée objet et également exécuter des arguments, vous pouvez procéder comme suit:
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()
Comme mentionné ci-dessus, cela pourrait également être fait avec 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()
L'avantage de cette méthode par rapport à une approche purement fonctionnelle est qu'elle vous permet de conserver votre autre code existant orienté objet. Le seul changement est de ne pas avoir la sous-classe Thread, ce qui ne devrait pas être un gros problème, car selon la documentation threading.Thread
:
écrase uniquement les méthodes init () et run () de cette classe
Si vous surchargiez Thread pour pouvoir accéder à l'objet thread à partir de votre sous-classe, nous vous recommandons d'utiliser simplement threading.currentThread () à partir de votre objet. De cette façon, vous segmentez l'espace de noms du fil du vôtre, et selon le "Zen of Python" de Tim Peters:
Les espaces de noms sont une bonne idée: faisons-en plus!
Afin de dissiper une certaine confusion quant au fait qu'une méthode run()
surchargée prenne des arguments supplémentaires, voici une implémentation d'une méthode run()
surchargée qui fait ce que la méthode héritée de threading.Thread
fait.
Notez, ceci juste pour voir comment on remplacerait run()
; ce n'est pas censé être un exemple significatif. Si vous souhaitez simplement appeler une fonction cible à l'aide d'arguments séquentiels et/ou de mots clés, il n'est pas nécessaire de créer une sous-classe. cela a été souligné par exemple dans la réponse de Jerub à cette question.
Le code suivant prend en charge Python v2 et v3.
Bien que l'accès aux noms d'attributs mutilés dans le code Python 2 soit particulièrement moche, je ne connais pas d'autre moyen d'accéder à ces attributs (laissez-moi savoir si vous en connaissez un ...):
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()
Il imprime (testé avec Python 2.6, 2.7 et 3.4 sous Windows 7):
func(): a=1, k=2
Comme l'argument constructeur du thread cible est appelable, appliquez __call__
comme méthode d'exécution.
class Worker(object):
def __call__(self, name, age):
print('name, age : ',name,age)
if __== '__main__':
thread = Thread(target=Worker(), args=('bob','50'))
thread.start()
sortie:
('name, age : ', 'bob', '50')
Vous définissez la méthode run pour accepter 3 arguments, mais vous l'appelez avec un seul argument (python l'appelle avec la référence à l'objet).
Vous devez transmettre les arguments à exécuter à la place de __init__
.
Ou demandez à la méthode __init__
d'accepter les arguments à la place.