>>> 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
'''
class MyClass:
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 | import new a.foo =new.instancemethod(foo, a, A) |
问题又来了,新加的方法里有调用实例的私有函数(以双下划线开头),报了如下错误:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | class A(): def__private(self): print "private"
defpublic(self): self.__private()
deffoo(self): self.__private()
a =A() import new 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 | class A(): def__private(self): print "private"
defpublic(self): self.__private()
deffoo(self): self.__private()
a =A() import dis dis.dis(a.public) a.public()
import new 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 | 6 0 LOAD_FAST 0 (self) 3LOAD_ATTR 0(_A__private) # a.public 6CALL_FUNCTION 0 9 POP_TOP 10LOAD_CONST 0(None) 13 RETURN_VALUE private 9 0 LOAD_FAST 0 (self) 3LOAD_ATTR 0(__private) # a.foo 6CALL_FUNCTION 0 9 POP_TOP 10LOAD_CONST 0(None) 13 RETURN_VALUE |
这里的原因是python会对private方法进行名字粉碎(name mangling) 。因此修改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
import new
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
>>>
---------------目前为止动态加的方法都不能访问实例的私有变量,除了加类名的方式