web-dev-qa-db-ja.com

オーバーライドpython threading.Thread.run()

PythonドキュメントThread.run()の場合:

サブクラスでこのメソッドをオーバーライドできます。標準のrun()メソッドは、ターゲット引数としてオブジェクトのコンストラクターに渡された呼び出し可能オブジェクトを呼び出します。引数がある場合は、それぞれargs引数とkwargs引数から引数を取得します。

次のコードを作成しました。

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

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

しかし、それを実行すると、次のエラーが表示されます。

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)

私は明らかな何かを見逃しているようですが、私が見たさまざまな例はこの方法論で動作します。最終的には、コンストラクタが正しい方法ではない場合、文字列と辞書をスレッドに渡すだけで、スレッドを開始する前に値を設定する新しい関数を作成しようとしています。

これを最善に達成するための提案はありますか?

36
Gavin M. Roy

スレッドをサブクラス化する必要はありません。 APIがこれをサポートする唯一の理由は、Javaから来た人がそれを気楽に行う唯一の方法である場合、より快適にするためです。

使用することをお勧めするパターンは、メソッドをThreadコンストラクターに渡し、単に.start()を呼び出すことです。

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

 thread = Thread(target=myfunc, args=(destination_name, destination_config))
 thread.start()
66
Jerub

以下は、__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()

そして、ここにマルチプロセッシングを使用した例があります:

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()
8
Gavin M. Roy

_threading.Thread_のドキュメントは、未使用の位置引数およびキーワード引数が実行に渡されることを暗示しているように見える場合があります。ではない。

余分な位置引数とキーワードkwargsは、デフォルトの_threading.Thread.__init___メソッドによって実際にトラップされますが、_target=_キーワードを使用して指定されたメソッドにのみ渡されます。それらはrun()メソッドに渡されません。

実際、 Threading documentation atは、それがisを呼び出すデフォルトのrun()メソッドであることを明確にしますトラップされた引数とkwargsを備えた提供された_target=_メソッド:

「サブクラスでこのメソッドをオーバーライドできます。標準のrun()メソッドは、オブジェクトのコンストラクターにターゲット引数として渡された呼び出し可能なオブジェクトを呼び出します(存在する場合)。

7
pjkundert

オーバーライドされたrun()メソッドが追加の引数を取るかどうかに関する混乱のいくつかに対処するために、threading.Threadから継承されたメソッドが行うことを行うオーバーライドされたrun()メソッドの実装があります。

これは、単にrun();をオーバーライドする方法を確認するためのものです。意味のある例ではありません。必要なのが、順次引数やキーワード引数を使用してターゲット関数を呼び出すことだけである場合、サブクラスを持つ必要はありません。これが指摘されていますin Jerub's answer この質問に対する。

次のコードは、Python v2とv3の両方をサポートしています。

特にPython 2コードのマングルされた属性名へのアクセスは見苦しいですが、これらの属性にアクセスする別の方法を知りません(知っていれば教えてください...):

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

表示されます(Windows 7ではPython 2.6、2.7、3.4でテスト済み):

func(): a=1, k=2
2
Andreas Maier

Threadコンストラクターの引数ターゲットは呼び出し可能オブジェクトなので、__call__ runメソッドとして

class Worker(object):
  def __call__(self, name, age):
    print('name, age : ',name,age)

if __== '__main__':

  thread = Thread(target=Worker(), args=('bob','50'))
  thread.start()

出力:

('name, age : ', 'bob', '50')
0
pmg7670

Runメソッドは3つの引数を受け入れるように定義しますが、1つの引数で呼び出します(Pythonはオブジェクトへの参照で呼び出します)。

__init__の代わりに実行する引数を渡す必要があります。

または、__init__メソッドが代わりに引数を受け入れるようにします。

0
Vasil