2009-03-19 29 views
28

Với Python documentation cho Thread.run():python Overriding 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.

tôi đã xây dựng đoạn mã sau:

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

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

Nhưng khi tôi thực hiện nó, tôi nhận được lỗi sau :

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) 

Có vẻ như tôi thiếu điều gì đó hiển nhiên, nhưng các ví dụ khác nhau Tôi đã thấy công việc với phương pháp này. Cuối cùng tôi đang cố gắng truyền chuỗi và từ điển vào trong chuỗi, nếu Constructor không đúng, nhưng để tạo một hàm mới để thiết lập các giá trị trước khi bắt đầu luồng, tôi mở nó ra.

Bất kỳ đề xuất nào về cách thực hiện tốt nhất điều này?

Trả lời

53

Bạn thực sự không cần phải phân lớp Chủ đề. Lý do duy nhất mà API hỗ trợ này là làm cho nó thoải mái hơn cho những người đến từ Java, đó là cách duy nhất để làm điều đó một cách an toàn.

Mẫu mà chúng tôi khuyên bạn sử dụng là chuyển một phương thức cho hàm tạo Thread và chỉ cần gọi .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

Đây là một thông tin quan trọng mà tôi đã bỏ lỡ, đó là lý do tại sao tôi chấp nhận nó, nhưng trong trường hợp của tôi, tôi thực sự đang mở rộng lớp thêm các chức năng cần thiết để kéo dữ liệu ra khỏi luồng. –

+3

Hàng nghìn lần có. Tôi phải giải thích điều này rất nhiều cho các nhà phát triển Java. –

+1

Bạn thậm chí không cần args = (arg1, arg2). Chỉ cần làm target = functools.partial (myfunc, arg1, arg2). – Phob

0

Bạn xác định phương thức chạy để chấp nhận 3 đối số, nhưng bạn gọi nó bằng một đối số (python gọi nó là tham chiếu đến đối tượng).

Bạn cần chuyển đối số để chạy thay vì __init__.

Hoặc làm cho phương thức __init__ chấp nhận các đối số thay thế.

+0

Bạn có chắc không? Tôi không nghĩ rằng bạn có thể vượt qua bất kỳ đối số để bắt đầu(). –

+0

Bạn không thể, tôi có nghĩa là chạy. Cảm ơn. – Vasil

+1

Không, tính năng này không hoạt động. Bạn không thể chuyển đối số tới start(), và toàn bộ vấn đề là bạn không thể gọi run() trực tiếp. – cmcginty

4

Tài liệu về threading.Thread có thể ngụ ý rằng bất kỳ vị trí không sử dụng và từ khóa nào được chuyển để chạy. Họ không phải.

Bất kỳ args vị trí bổ sung nào và từ khóa kwargs thực sự bị bẫy theo phương thức mặc định threading.Thread.__init__, nhưng chúng chỉ được chuyển đến phương thức được chỉ định sử dụng từ khóa target=. Chúng KHÔNG được chuyển sang phương thức run().

Trong thực tế, Threading documentation tại làm cho nó rõ ràng rằng nó mặc định phương pháp run() để gọi cung cấp target= phương pháp với args bị mắc kẹt và 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

Tôi đồng ý. Một số câu trả lời khác cho câu hỏi ban đầu có được điều này sai (những người hiển thị một phương thức 'run()' với các đối số ngoài 'self'). –

7

Dưới đây là là một ví dụ về lập luận qua sử dụng luồng và không mở rộng __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() 

Và đây là ví dụ sử dụng 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

Truy cập 'self._Thread__kwargs' rất xấu. – glglgl

+0

Trong Python 3, các thuộc tính của Thread được thay đổi từ private thành protected, tức là 'self .__ kwargs' (trong lớp Thread) trở thành' self._kwargs'. Điều này cho phép truy cập ít xấu xí hơn, bởi vì tên mangling không còn được sử dụng nữa. Tuy nhiên, thay đổi này yêu cầu một phiên bản Python phải nhạy cảm nếu muốn hỗ trợ cả Python 2 và 3. –

+0

Một điều nữa: Tôi không thấy cách có thể triển khai phương thức 'run()' bị ghi đè ** mà không ** truy cập trực tiếp các thuộc tính Thread '_target',' _args' và '_kwargs' (sử dụng tên v3 của chúng): Giá trị của chúng phải được sử dụng (xem mô tả run() đã được trích dẫn trong các phản hồi khác), và chúng không có accessor phương pháp. –

0

Nếu bạn muốn giữ cách tiếp cận hướng đối tượng của bạn và cũng có lý lẽ chạy, bạn có thể làm như sau:

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

Như đã đề cập ở trên, nó cũng có thể được thực hiện với 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ợi thế của việc này so với cách tiếp cận thuần túy là nó cho phép bạn giữ mã hướng đối tượng hiện tại của bạn giống nhau. Sự thay đổi duy nhất là để có nó không phân lớp Chủ đề, mà không phải là một vấn đề lớn, vì mỗi threading.Thread tài liệu:

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

Nếu bạn được trọng Chủ đề để bạn có thể truy cập vào đối tượng thread từ bên trong lớp con của bạn, sau đó tôi khuyên bạn chỉ nên sử dụng threading.currentThread() từ bên trong đối tượng của bạn. Bằng cách này bạn phân khúc namespace của chủ đề từ của riêng bạn, và theo "Zen của Python" bởi Tim Peters:

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

2

Để giải quyết một số sự nhầm lẫn về việc liệu một ghi đè run() phương pháp lấy đối số bổ sung, đây là việc triển khai phương thức run() đã ghi đè thực hiện những gì phương thức được kế thừa từ threading.Thread.

Lưu ý, điều này chỉ để xem cách người ta ghi đè run(); nó không phải là một ví dụ có ý nghĩa. Nếu tất cả những gì bạn muốn làm là gọi một hàm đích với các tham số tuần tự và/hoặc từ khóa, thì không cần thiết phải có một lớp con; điều này đã được chỉ ra, ví dụ: trong Jerub's answer cho câu hỏi này.

Mã sau hỗ trợ cả Python v2 và v3.

Mặc dù đặc biệt là truy cập vào các tên thuộc tính đọc sai trong các mã Python 2 là xấu xí, tôi không nhận thức được một cách khác để truy cập vào các thuộc tính (cho tôi biết nếu bạn biết một ...):

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

Bản in được in (được thử nghiệm với Python 2.6, 2.7 và 3.4 trên Windows 7):

func(): a=1, k=2