2012-11-24 27 views
6

Làm cách nào để "lấy cắp" hoặc sao chép một phương thức từ một lớp học sang một lớp khác?Cách đánh cắp phương pháp python

Ví dụ mã:

class A(object): 
    def foo(self): 
    print "blah" 


class B(object): 
    foo = A.foo 

B().foo() 

Dự kiến ​​sản lượng:

"blah" 

Thay vào đó:

TypeError: unbound method foo() must be called with A instance as first argument (got nothing instead)

+1

Điều này sẽ có ý nghĩa hơn nếu 'foo' là một phương thức lớp thay vì một phương thức thể hiện. – NullUserException

Trả lời

6

Sử dụng __func__:

>>> A.foo 
<unbound method A.foo> 
>>> A.foo.__func__ 
<function foo at 0x00BC5F70> 
>>> class B(object): 
... foo = A.foo.__func__ 
... 
>>> B().foo() 
"blah" 

Trích dẫn the docs:

An instance method object combines a class, a class instance and any callable object (normally a user-defined function).

Special read-only attributes: __self__ is the class instance object, __func__ is the function object; __doc__ is the method’s documentation (same as __func__.__doc__); __name__ is the method name (same as __func__.__name__); __module__ is the name of the module the method was defined in, or None if unavailable.

+0

Hoặc, anh ta cũng có thể làm 'A(). Foo' thay vì' A.foo .__ func__'. – jdotjdot

+2

@jdotjdot 'A(). Foo' là một phương thức" ràng buộc ", gắn với trường hợp cụ thể của' A'. Điều đó không quan trọng trong ví dụ (có lẽ đã đơn giản hóa) - vì nó không sử dụng 'self', và có thể được thay thế bằng một phương thức static/class - nhưng trong các kịch bản phức tạp hơn nó sẽ xảy ra. Tôi giả sử ý định của OP, mặc dù không được nêu ra, là chọn một phương thức hữu ích từ một lớp tùy ý (nghĩa là không được kế thừa từ và không phải là mixin) và có cùng phương thức trong lớp của riêng mình, nhưng đề cập đến/hành động trên các trường hợp của lớp học của mình - và không phải của bản gốc. – mgibsonbr

+0

bạn nói đúng. Tôi đã suy nghĩ về điều này ví dụ cụ thể, vì 'tự' là không cần thiết - nhưng bạn chắc chắn phải trong đó trong trường hợp tổng quát, 'A(). Foo' không phải là một cuộc gọi tốt. – jdotjdot

1

Bạn có thể sử dụng class inheritance đây. Thừa kế cho phép bạn tạo một đối tượng dựa trên một đối tượng khác, kế thừa tất cả các hàm và thuộc tính của nó.

Trong trường hợp này, nó trông giống như:

class A(object): 
    def foo(self): 
    print "blah" 


class B(A): 
    # You can add new methods or attributes here, 
    # or even overwrite those inherited from A if you 
    # really want to, though you have to be careful with that. 
    pass 

Sau khi tuyên bố rằng,

>>> B().foo() 
"blah" 

này hoạt động bởi vì:

  • Bạn tạo lớp A, và tạo cho nó một phương pháp foo.
  • Bạn tạo lớp Bkế thừa từ A, có nghĩa là khi A "đã sinh ra nó," B được sinh ra với tất cả những gì A có.
    • Trong trường hợp của chúng tôi, B là bản sao chính xác của A, vì chúng tôi không làm bất kỳ điều gì khác với nó. Tuy nhiên, chúng tôi có thể thực hiện thay đổi hoặc thêm các phương pháp khác.

Một ví dụ:

class A(object): 
    def foo(self): 
     print "blah" 

class B(A): 
    def newfoo(self): 
     print "class A can't do this!" 

nào được sử dụng, chúng ta sẽ thấy:

>>> A().foo() 
blah 
>>> B().foo() 
blah 
>>> A().newfoo() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: 'A' object has no attribute 'newfoo' 
>>> B().newfoo() 
class A can't do this! 

Đặc biệt, lý do mà mã của bạn ở trên đã không làm việc là khi bạn cố gắng đặt B.foo, bạn đã viết

class B(object): 
    foo = A.foo 

thay vì

class B(object): 
    foo = A().foo 

Khi bạn đã viết A.foo mà không (), bạn được yêu cầu phương pháp trực tiếp từ Aloại, trong đó sẽ không làm việc trong Python. Nếu bạn đã làm foo = A().foo, điều bạn sẽ làm là khởi tạo đối tượng A và sau đó nhận bản sao phương thức foo và sau đó gán nó.

2

Vấn đề ở đây là nó là một phương pháp ràng buộc bạn đang cố gắng để ăn cắp, tuy nhiên, ví dụ của bạn không liên quan đến một chức năng mà sử dụng trạng thái cá thể (self). Do đó bạn có hai lựa chọn ngay lập tức:

  1. Hãy định nghĩa của A.foo một phương pháp tĩnh (@staticmethod trang trí)
  2. trang trí hoặc quấn chức năng để vượt qua một cuộc tranh cãi không sử dụng. Ví dụ. sử dụng functools.

Ví dụ:

import functools 
stolen = functools.partial(A.foo, None) 

Điều này làm việc vì phương pháp của bạn không sử dụng trạng thái mẫu và không yêu cầu tạo phân lớp.

Để tô điểm thêm một chút, phương pháp thể hiện bị ràng buộc (như A.foo) dự kiến ​​đối số mẫu được ràng buộc (self, trong đó bản thân là một phiên bản A). Trong sử dụng bình thường, số đầu tiên này được truyền tự động:

a = A() 

Bây giờ là:

a.foo() 
A.foo(a) 

... Có cả tương đương. Trong trường hợp đầu tiên, cú pháp instance.bound_method() infers InstanceClass.bound_method(instance) từ quan điểm từ vựng (instance giải quyết thành self). Đây là lý do tại sao gọi A.foo() sẽ gây ra lỗi, vì nó dự kiến ​​một phiên bản của A.

Giải pháp trên là làm cong chức năng thành một trong đó vượt qua None làm ví dụ, vì bản sao không bao giờ được sử dụng (không có logic dựa trên trạng thái). Trong trường hợp sử dụng staticmethod, nó loại bỏ đối số ví dụ ràng buộc được ngụ ý thứ nhất ngụ ý self.

Các vấn đề liên quan