python中实例动态绑定的方法访问私有方法
python有一个编译好的模块,需要增加一个方法。由于不想修改源代码再编译,所以使用动态绑定方法来给实例增加方法。
第一印象,想到使用如下方法:
def foo(self): print self.name a = A() a.foo = foo
>>> a.foo() Traceback (most recent call last): File "", line 1, in TypeError: foo() takes exactly 1 argument (0 given)
结果是无法访问实例的变量。 比较新绑定的方法与原有的实例方法,发现原有的实例方法是bound method。只有bound method才能访问实例的变量。
要动态为实例绑定方法,可以使用new模块(http://docs.python.org/library/new.html)。 (文档中说new模块已经过期,推荐使用types模块。但我看types的文档,想不明白如何取代new模块)
import new a.foo = new.instancemethod(foo, a, A)
问题又来了,新加的方法里有调用实例的私有函数(以双下划线开头),报了如下错误:
class A():
def __private(self):
print "private"
def public(self):
self.__private()
def foo(self):
self.__private()
a = A()
import new
a.foo = new.instancemethod(foo, a, A)
a.foo()
Traceback (most recent call last): File "E:tmptest.py", line 14, ina.foo() File "E:tmptest.py", line 9, in foo self.__private() AttributeError: A instance has no attribute '__private'
通过观察原有方法和动态绑定方法的字节码,发现LOAD_ATTR有差别。原有方法的LOAD_ATTR是“_A__private”,动态绑定的方法的LOAD_ATTR是“__private”
class A():
def __private(self):
print "private"
def public(self):
self.__private()
def foo(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()
6 0 LOAD_FAST 0 (self)
3 LOAD_ATTR 0 (_A__private) # a.public
6 CALL_FUNCTION 0
9 POP_TOP
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
private
9 0 LOAD_FAST 0 (self)
3 LOAD_ATTR 0 (__private) # a.foo
6 CALL_FUNCTION 0
9 POP_TOP
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
这里的原因是python会对private方法进行名字粉碎(name mangling) 。因此修改foo方法里面的调用为self._A__private(),通过。但这样修改后,方法对于不同的class会不通用,有待研究更好的方法