python中為類和例項動態增加方法
>>> def func(a,b):
... print a,b
...
>>> class Foo(object):
... pass
...
>>> foo = Foo()
>>> foo.func(4)
Traceback (most recent call last):
File "<input>", line 1, in <module>
AttributeError: 'Foo' object has no attribute 'func'
>>> Foo.func = func #類動態增加方法一:直接賦值
>>> Foo.func
<unbound method Foo.func>
>>>
>>> foo.func(4)
<__main__.Foo object at 0x3f79db0> 4
>>> foo.func
<bound method Foo.func of <__main__.Foo object at 0x3f79db0>>
>>> foo.func2=func #
>>> foo.func2
<function func at 0x3f66df0>
>>> foo.func2(1,2)
1 2
>>> foo.func2(4)
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: func() takes exactly 2 arguments (1 given)
>>> import new
>>> foo.func3 = new.instancemethod(func,foo,Foo)#例項動態增加方法一:
>>> foo.func3
<bound method Foo.func of <__main__.Foo object at 0x3f79db0>>
>>> foo.func3(4)
<__main__.Foo object at 0x3f79db0> 4
>>> dir(Foo)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'func']
>>> dir(foo)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'func', 'func2', 'func3']
>>>
http://wendal.net/351.html
Python: 為物件動態新增函式,且函式定義來自一個str
在Python中,通常情況下,你只能為物件新增一個已經寫好的方法
需求:傳入一個str型別的變數,其值是一個完整的合法的Python函式定義,然後為一個物件新增這個函式:
method_str = u'''
def say(self, name)
print 'My nameis', name
'''
classMyClass:
def __init__(self):
pass
def extends(self, method_name, method_str):
#完成這個方法...
obj =MyClass();
obj.extends('say', method_str)
obj.say('wendal')#打印出My name is wendal
想了不少路子,在Python的QQ群裡面也得到不少靈感,最後順利實現:
def extends(sefl, method_name, method_str):
#_method = None
exec method_str + '''\n_method = %s''' % method_name
self.__dict__[method_name]= new.instancemethod(_method,self, None)
簡單解釋一下: method_str在exec前,改變為:
method_str = u'''
def say(self, name)
print 'My nameis', name
_method = abc
然後, exec執行後,_method變數就賦值為say函式接下來,就是Python的自省機制了,通過new模組,生成特定物件(本例中是self)的例項方法最後,為特定物件新增say這個函式
恩,這例子,就足以體現出Python在這方面的擴充套件性 1. method_str是一個字串,可以動態建立,例如使用者輸出,模板生成 2. 方法的名字可以通過字串分割等方法獲取到
昨晚完成這個實現之後,足足興奮了一個小時,哈哈 – 2行程式碼就搞定!!
http://blog.lzhaohao.info/archive/python-dynamic-instance-bound-method-access-to-private-method/
python中例項動態繫結的方法訪問私有方法
Posted in python On 2011-05-24 09:46:59 , tagged withpython.
python有一個編譯好的模組,需要增加一個方法。由於不想修改原始碼再編譯,所以使用動態繫結方法來給例項增加方法。
第一印象,想到使用如下方法:
1 2 3 4 5 |
deffoo(self): print self.name a =A() a.foo =foo |
1 2 3 4 |
>>> a.foo() Traceback (most recent call last): File"<stdin>", line 1, in<module> TypeError: foo() takes exactly 1argument (0given) |
結果是無法訪問例項的變數。比較新繫結的方法與原有的例項方法,發現原有的例項方法是bound method。只有bound method才能訪問例項的變數。
要動態為例項繫結方法,可以使用new模組(http://docs.python.org/library/new.html)。(文件中說new模組已經過期,推薦使用types模組。但我看types的文件,想不明白如何取代new模組)
1 2 |
importnew a.foo =new.instancemethod(foo, a, A) |
問題又來了,新加的方法裡有呼叫例項的私有函式(以雙下劃線開頭),報瞭如下錯誤:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
classA(): def__private(self): print "private" defpublic(self): self.__private() deffoo(self): self.__private() a =A() importnew a.foo =new.instancemethod(foo, a, A) a.foo() |
1 2 3 4 5 6 |
Traceback (most recent call last): File"E:tmptest.py", line 14, in<module> a.foo() File"E:tmptest.py", line 9,infoo self.__private() AttributeError: A instance has no attribute '__private' |
通過觀察原有方法和動態繫結方法的位元組碼,發現LOAD_ATTR有差別。原有方法的LOAD_ATTR是“_A__private”,動態繫結的方法的LOAD_ATTR是“__private”
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
classA(): def__private(self): print "private" defpublic(self): self.__private() deffoo(self): self.__private() a =A() importdis dis.dis(a.public) a.public() importnew a.foo =new.instancemethod(foo, a, A) dis.dis(a.foo) a.foo() |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
60LOAD_FAST 0(self) 3LOAD_ATTR 0(_A__private) # a.public 6CALL_FUNCTION 0 9 POP_TOP 10LOAD_CONST 0(None) 13 RETURN_VALUE private 90LOAD_FAST 0(self) 3LOAD_ATTR 0(__private) # a.foo 6CALL_FUNCTION 0 9 POP_TOP 10LOAD_CONST 0(None) 13 RETURN_VALUE |
這裡的原因是python會對private方法進行名字粉碎。因此修改foo方法裡面的呼叫為self._A__private(),通過。但這樣修改後,方法對於不同的class會不通用,有待研究更好的方法
http://outofmemory.cn/code-snippet/2856/python-dongtai-modify-class-method-execution-logical
python動態修改類方法的執行邏輯
下面的程式碼演示如何給已經定義好的python類新增方法,替代已有方法:
from __future__ import nested_scopes
importnew
def enhance_method(klass, method_name, replacement):
'替代已有的方法'
method = getattr(klass, method_name)
setattr(klass, method_name, new.instancemethod(
lambda *args, **kwds: replacement(method, *args, **kwds),None, klass))
def method_logger(old_method, self, *args, **kwds):
'給方法新增呼叫執行日誌'
print '*** calling: %s%s, kwds=%s' % (old_method.__name__, args, kwds)
return_value = old_method(self, *args, **kwds)# call the original method
print'*** %s returns: %s' % (old_method.__name__, `return_value`)
return return_value
def demo():
class Deli:
def order_cheese(self, cheese_type):
print'Sorry, we are completely out of %s' % cheese_type
d = Deli()
d.order_cheese('Gouda')
enhance_method(Deli, 'order_cheese', method_logger)
d.order_cheese('Cheddar')
當需要修改第三方python包的某個類的某個方法時,這種修改方式非常有用。
-----------setattr方法-------------
>>> def func3(self, a):
... print self.__a
...
>>> def func4(self,b):
... print self._b
...
>>> def func5(self,c):
... print self.c
...
>>> class Foo(object):
... def __init__(self):
... self.__a = 3
... self._b=4
... self.c=5
... def printme(self):
... print self.__a, self._b, self.c
...
>>> foo = Foo()
>>> foo.printme()
3 4 5
>>> foo.funcc=new.instancemethod(func5,foo,Foo)
>>> foo.funcc(5)
5
>>> foo.funcb=new.instancemethod(func4,foo,Foo)
>>> foo.funcb(4)
4
>>> foo.funca=new.instancemethod(func3,foo,Foo)
>>> foo.funca(3)
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "<input>", line 2, in func3
AttributeError: 'Foo' object has no attribute '__a'
>>> foo.funcx=new.instancemethod(func3,foo,None)
>>> foo.funcx(0)
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "<input>", line 2, in func3
AttributeError: 'Foo' object has no attribute '__a'
>>> setattr(foo,'funcy',func3.__get__(foo,Foo))
>>> foo.funcy
<bound method Foo.func3 of <__main__.Foo object at 0x3f81730>>
>>> foo.funcy(3)
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "<input>", line 2, in func3
AttributeError: 'Foo' object has no attribute '__a'
>>>
>>> def func6(self,a):
... print self._Foo__a
...
>>> foo.funcz=new.instancemethod(func6,foo,None)
>>> foo.funcz(6)
3
>>>
---------------目前為止動態加的方法都不能訪問例項的私有變數,除了加類名的方式