2009-06-18 31 views
92

Trong Python, có cách nào để ràng buộc một phương thức không liên kết mà không gọi nó?Python: Liên kết một phương thức chưa được gửi?

Tôi đang viết một chương trình wxPython, và cho một lớp nào đó tôi quyết định nó muốn được tốt đẹp để nhóm dữ liệu của tất cả các nút của tôi với nhau như một danh sách lớp cấp của các bộ, như vậy:

class MyWidget(wx.Window): 
    buttons = [("OK", OnOK), 
       ("Cancel", OnCancel)] 

    # ... 

    def Setup(self): 
     for text, handler in MyWidget.buttons: 

      # This following line is the problem line. 
      b = wx.Button(parent, label=text).Bind(wx.EVT_BUTTON, handler) 

Vấn đề là, vì tất cả các giá trị của handler là các phương pháp không liên kết, chương trình của tôi phát nổ trong một ngọn lửa ngoạn mục và tôi khóc.

Tôi đang tìm kiếm trực tuyến giải pháp cho những gì có vẻ như là một vấn đề tương đối đơn giản, có thể giải quyết được. Thật không may tôi không thể tìm thấy bất cứ điều gì. Ngay bây giờ, tôi đang sử dụng functools.partial để giải quyết vấn đề này, nhưng có ai biết nếu có một cảm giác sạch sẽ, khỏe mạnh, Pythonic để liên kết một phương pháp không ràng buộc với một cá thể và tiếp tục truyền xung quanh mà không gọi nó?

+1

Xác định "phương pháp không ràng buộc" – Christopher

+4

@Christopher - Một phương pháp mà không bị ràng buộc với phạm vi của đối tượng đó được hút từ, vì vậy bạn phải vượt qua tự một cách rõ ràng. –

Trả lời

143

Tất cả các chức năng cũng mô tả, vì vậy bạn có thể ràng buộc họ bằng cách gọi phương pháp __get__ của họ:

bound_handler = handler.__get__(self, MyWidget) 

Dưới đây là tuyệt vời guide để mô tả R. hettinger của.

+2

Điều đó khá thú vị. Tôi thích cách bạn có thể bỏ qua loại và lấy lại phương thức "ràng buộc" .f ". – Kiv

+0

Tôi thích giải pháp này trên 'MethodType', vì nó hoạt động tương tự trong py3k, trong khi các đối số' MethodType' đã được thay đổi một chút. – bgw

+8

Và do đó, một hàm để liên kết các hàm với các cá thể lớp: 'bind = lambda instance, func, asname: setattr (ví dụ, asname, func .__ get __ (instance, instance .__ class __))' Ví dụ: 'class A: vượt qua; ' ' a = A(); ' ' ràng buộc (a, ràng buộc, 'ràng buộc') ' –

3

này sẽ ràng buộc self-handler:

bound_handler = lambda *args, **kwargs: handler(self, *args, **kwargs) 

này hoạt động bằng cách truyền self như là đối số đầu tiên của hàm. object.function() chỉ là cú pháp đường cho function(object).

+1

Có, nhưng điều này gọi phương thức. Vấn đề là tôi cần để có thể vượt qua các phương pháp ràng buộc như là một đối tượng có thể gọi. Tôi có phương pháp không ràng buộc và ví dụ tôi muốn nó được ràng buộc, nhưng không thể tìm ra cách để đặt tất cả lại với nhau mà không gọi ngay là –

+6

Không, nó sẽ chỉ gọi phương thức nếu bạn làm bound_handler(). Định nghĩa một lambda không gọi lambda. –

+0

Bạn thực sự có thể sử dụng 'functools.partial' thay vì định nghĩa một lambda. Tuy nhiên, nó không giải quyết được vấn đề chính xác. Bạn vẫn đang xử lý một 'hàm' thay vì' instancemethod'. –

68

Điều này có thể được thực hiện một cách rõ ràng với types.MethodType. Ví dụ:

import types 

def f(self): print self 

class C(object): pass 

meth = types.MethodType(f, C(), C) # Bind f to an instance of C 
print meth # prints <bound method C.f of <__main__.C object at 0x01255E90>> 
+8

+1 Điều này thật tuyệt, nhưng không có tham chiếu đến nó trong tài liệu python tại URL bạn đã cung cấp. –

+2

+1, tôi không muốn gọi hàm ma thuật trong mã của mình (tức là '__get__'). Tôi không biết phiên bản python nào bạn đã thử nghiệm này, nhưng trên trăn 3.4, hàm 'MethodType' lấy hai đối số. Hàm và thể hiện. Vì vậy, điều này nên được thay đổi thành 'types.MethodType (f, C())'. –

+0

Đây rồi! Đó là một cách tốt để vá các phương thức ví dụ: 'wgt.flush = types.MethodType (lambda self: None, wgt)' – Winand

7

Tạo một bao đóng với chính nó sẽ không ràng buộc về mặt kỹ thuật hàm, nhưng nó là một cách khác để giải quyết cùng một vấn đề cơ bản (hoặc rất giống). Dưới đây là một ví dụ nhỏ:

self.method = (lambda self: lambda args: self.do(args))(self) 
Các vấn đề liên quan