2012-11-24 50 views
6

我該如何「偷」或將一個方法從一個類複製到另一個類?python method stealer

示例代碼:

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


class B(object): 
    foo = A.foo 

B().foo() 

預期輸出:

"blah" 

相反:

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

+1

如果'foo'是類方法而不是實例方法,這會更有意義。 – NullUserException

回答

6

使用__func__

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

報價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

或者,他也可以只做'A()。foo'而不是'A.foo .__ func__'。 – jdotjdot

+2

@jdotjdot'A()。foo'是一個「綁定方法」,綁定到'A'的特定實例。這在(可能是簡化的)例子中並不重要 - 因爲它不使用'self',並且可以用靜態/類方法代替 - 但是在更復雜的情況下它會。我假定OP的意圖雖然沒有說明,但是從任意類中選擇一種有用的方法(即不意味着從繼承而不是混合),並且在他自己的類中有相同的方法,但是指/根據他的班級實例行事 - 而不是原來的行爲。 – mgibsonbr

+0

你是對的。我正在考慮這個具體的例子,因爲'self'不是必需的 - 但你肯定是對的,因爲在廣義的情況下,'A().foo'不是一個好的調用。 – jdotjdot

1

可以使用class inheritance這裏。繼承允許您基於另一個對象創建一個對象,並繼承它的所有功能和屬性。

在這種情況下,它看起來像:

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 

該聲明後,

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

這樣做是因爲:

  • 你創造A類,並創建了它方法foo
  • 您創建BA繼承,這意味着當A「生下它,」 B誕生與A擁有一切。
    • 在我們的案例中,BA的精確副本,因爲我們沒有做任何其他的事情。但是,我們可以進行更改或添加更多方法。

一個例子:

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

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

,在使用中,我們會看到:

>>> 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! 

特別是,你的代碼上面沒有工作的原因是,當你試圖設置B.foo時,你寫了

class B(object): 
    foo = A.foo 

代替

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

當你寫A.foo沒有(),你是從的A類型,它不會在Python工作直接詢問的方法。如果你要做foo = A().foo,你會做的是實例化一個A對象,然後獲取其方法foo的副本,然後分配它。

2

這裏的問題是,它是你偷一個綁定的方法,但是,你的例子不涉及功能使用實例狀態(self)。因此,你有兩個直接的選擇:

  1. 使A.foo定義一個靜態方法(@staticmethod裝飾)
  2. 裝飾或包裹的函數傳遞一個未使用的參數。例如。使用functools

例如,

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

這是有效的,因爲您的方法不使用實例狀態,也不需要創建子類。

若要進一步修飾,綁定實例方法(如A.foo)需要綁定實例參數(self,其中self是A的實例)。在正常使用的情況,這第一個參數自動傳遞:現在

a = A() 

a.foo() 
A.foo(a) 

...都是等價的。在第一種情況下,語法instance.bound_method()從詞彙的角度推斷InstanceClass.bound_method(instance)instance解析爲self)。這就是爲什麼調用A.foo()會導致錯誤,因爲它期望A的實例。

上面的解決方案是將函數轉換爲一個傳遞None作爲實例的函數,因爲實例從來沒有被使用過(沒有基於狀態的邏輯)。在使用靜態方法的情況下,它將刪除第一個隱含的期望綁定實例參數self