2014年6月27日 星期五

[Python]動態在Object中加入Method

Python這類的動態語言大多提供Run-time時動態修改一個object的方法,這樣的好處是你可以動態的修改某個object,為這個Obejct加入一些新的method。

Ruby要為object加入新method非常簡單:

dog = Object.new

def dog.sit
    print "I'm sitting.\n"
end

dog.sit

Ruby很簡單就能為dog加入一個sit的method。
Python實做起來稍微麻煩一些,主要原因是因為Python的函式有分成bound和unbound。

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

bound method必須被bound到一個instance,在呼叫method時instance才會被當成參數傳入。
由於函式預設都是Unbound,如果直接加入method到object中,Python會丟出exception

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

其實只需要手動把method bound到instance上就可以解決這個問題。
這邊我們使用type module中的MethodType來把method bound到instance上。

>>> import types
>>> a.barFighters = types.MethodType( barFighters, a )
>>> a.barFighters
<bound method ?.barFighters of <__main__.A instance at 0x00A9BC88>>
>>> a.barFighters()
barFighters

可以看到method被bound後就可以在Python中被正確的呼叫,這就是Python動態在object加入method的方法。