Điều đầu tiên là nhận được tên một cách chính xác:
>>> def increment(obj):
... obj.count += 1
...
>>> class A(object):
... def __init__(self):
... self.count = 0
...
>>> o = A()
>>> o.__init__
<bound method A.__init__ of <__main__.A object at 0x0000000002766EF0>>
>>> increment
<function increment at 0x00000000027797C8>
tên Vì vậy, đúng là chức năng và phương pháp ràng buộc. Bây giờ bạn có thể tìm kiếm làm thế nào để Bind an Unbound Method và có thể bạn sẽ kết thúc đọc về descriptors:
Nói chung, một bộ mô tả là một thuộc tính đối tượng với "ràng buộc hành vi", một người có thuộc tính truy cập đã được ghi đè bằng các phương pháp trong giao thức mô tả. Những phương pháp đó là __get__
, __set__
và __delete__
. Nếu bất kỳ phương thức nào trong số đó được định nghĩa cho một đối tượng, nó được gọi là một bộ mô tả.
Bạn có thể dễ dàng chuyển đổi chức năng để phương pháp bằng cách chỉ sử dụng gọi khác nhau của __get__
>>> increment.__get__(None, type(None))
<function increment at 0x00000000027797C8>
>>> increment.__get__(o, type(o))
<bound method A.increment of <__main__.A object at 0x00000000027669B0>>
Và nó hoạt động như một nét duyên dáng:
>>> o = A()
>>> increment.__get__(None, type(None))(o)
>>> o.count
1
>>> increment.__get__(o, type(o))()
>>> o.count
2
Bạn có thể dễ dàng thêm các phương pháp mới bao bọc đối tượng:
def increment(obj):
obj.count += 1
def addition(obj, number):
obj.count += number
class A(object):
def __init__(self):
self.count = 0
o = A()
o.inc = increment.__get__(o)
o.add = addition.__get__(o)
print(o.count) # 0
o.inc()
print(o.count) # 1
o.add(5)
print(o.count) # 6
Hoặc tạo riêng mô tả của bạn mà sẽ sẽ chuyển đổi chức năng-phương pháp ràng buộc:
class BoundMethod(object):
def __init__(self, function):
self.function = function
def __get__(self, obj, objtype=None):
print('Getting', obj, objtype)
return self.function.__get__(obj, objtype)
class B(object):
def __init__(self):
self.count = 0
inc = BoundMethod(increment)
add = BoundMethod(addition)
o = B()
print(o.count) # 0
o.inc()
# Getting <__main__.B object at 0x0000000002677978> <class '__main__.B'>
print(o.count) # 1
o.add(5)
# Getting <__main__.B object at 0x0000000002677978> <class '__main__.B'>
print(o.count) # 6
Và bạn cũng có thể thấy rằng đây là độc đáo phù hợp với function/bound method principles:
Lớp từ điển lưu trữ các phương thức như hàm. Trong định nghĩa lớp, các phương thức được viết bằng cách sử dụng def và lambda, các công cụ thông thường để tạo các hàm. Sự khác biệt duy nhất từ các hàm thông thường là đối số đầu tiên được dành riêng cho cá thể đối tượng. Theo quy ước Python, tham chiếu cá thể được gọi là tự nhưng có thể được gọi là tên này hoặc bất kỳ tên biến nào khác.
Để hỗ trợ các cuộc gọi phương thức, các hàm bao gồm phương thức __get__()
cho các phương thức liên kết trong khi truy cập thuộc tính. Điều này có nghĩa là tất cả các hàm đều là các bộ mô tả phi dữ liệu trả về các phương thức bị ràng buộc hoặc không liên kết phụ thuộc vào việc chúng được gọi từ một đối tượng hay một lớp.
Và chức năng trở thành phương pháp ràng buộc trong dụ khởi tạo:
>>> B.add
# Getting None <class '__main__.B'>
<function addition at 0x00000000025859C8>
>>> o.add
# Getting <__main__.B object at 0x00000000030B1128> <class '__main__.B'>
<bound method B.addition of <__main__.B object at 0x00000000030B1128>>
Tôi có vấn đề này cố gắng xây dựng một lớp Heapq sử dụng xấu xí module 'heapq'. Giải pháp của bạn là tốt. Nó có thể được thực hiện trong một dòng, nhưng có cùng hiệu quả: 'def method_wraper (f): trả về functools.wraps (f) (lambda * a, ** kw: f (* a, ** kw))' – JBernardo
. ..Interesting, việc gán dường như hoạt động tốt nếu hàm được định nghĩa trong cùng một mô-đun (phương thức không liên kết được gán cho một lớp và ràng buộc trên instantiation). Vì vậy, nó chỉ là một vấn đề với phần mở rộng C, hoặc với các chức năng trong các mô-đun khác nhau? Dù sao, bạn có thể muốn xem http://stackoverflow.com/questions/7490879/python3-bind-method-to-class-instance-with-get-it-works-but-why, điều này có thể giúp bạn một chút cũng. – JAB
Ngoài ra, http://docs.python.org/py3k/howto/descriptor.html#functions-and-methods "việc thực hiện C thực tế của PyMethod_Type trong Objects/classobject.c là một đối tượng duy nhất có hai biểu diễn khác nhau tùy thuộc vào việc trường im_self được thiết lập hoặc là NULL (tương đương C của None). " Mà làm cho nó có vẻ như vấn đề này không nên xảy ra ở tất cả, trừ khi Python bằng cách nào đó không cập nhật trực tiếp lĩnh vực đó cho một phương pháp của đối tượng khi instantiating đối tượng. – JAB