注:本文轉譯自 Stackoverflow 上 Adding a Method to an Existing Object 的最佳回答。
在 python 中,def 定義的函數與類中的方法有很大的不同,兩者是不同的類型。
>>> def foo():
... print "foo"
...
>>> class A:
... def bar( self ):
... print "bar"
...
>>> a = A()
>>> foo
<function foo at 0x00A98D70>
>>> a.bar
<bound method A.bar of <__main__.A instance at 0x00A9BC88>>
>>>
類中的方法是綁定方法,會具體綁定到某一類的實例。當方法被調用時,實例對象會作為第一個參數(self),被傳入到方法中。
一個類中的可調用屬性一直是未綁定,當類被實例化為一個對象時才綁定到某一具體實例上。所以我們可以在任何時候對類中已定義的方法進行修改。
>>> def fooFighters( self ):
... print "fooFighters"
...
>>> A.fooFighters = fooFighters
>>> a2 = A()
>>> a2.fooFighters
<bound method A.fooFighters of <__main__.A instance at 0x00A9BEB8>>
>>> a2.fooFighters()
fooFighters
在修改之前已經實例化的對象也會改變(只要它們沒有覆蓋自身屬性)。新添加的方法會自動與實例對象進行綁定。
>>> a.fooFighters()
fooFighters
這種直接添加或修改類中的方法只能在類上進行修改,如果只想給一個實例化的對象增加方法就會產生問題。
>>> def barFighters( self ):
... print "barFighters"
...
>>> a.barFighters = barFighters
>>> a.barFighters()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: barFighters() takes exactly 1 argument (0 given)
當把方法直接添加到一個實例對象時,函數並沒有自動與與實例對象進行綁定。其仍然是一個函數類型,而不是一個綁定方法 (bound method)。
>>> a.barFighters
<function barFighters at 0x00A98EF0>
我們可以使用 types
模塊中的 MethodType
函數顯示綁定函數到某一個實例對象上。
>>> import types
>>> a.barFighters = types.MethodType( barFighters, a )
>>> a.barFighters
<bound method ?.barFighters of <__main__.A instance at 0x00A9BC88>>
>>> a.barFighters()
barFighters
這樣修改只改變了實例 a 的方法,不會影響到其他實例。