简短版本:绑定到实例的外部方法不能直接通过self.__privatevarname
. 这是功能还是错误?
扩展版(带解释和示例):
在Python 中:绑定一个未绑定的方法?, Alex Martelli 解释了一种将函数绑定到实例的简单方法。
使用这种方法,可以使用外部函数在类中设置实例方法(in __init__
)。
但是,当绑定到实例的函数需要访问私有变量时,这种方法就会失效。这是因为名称修改发生在编译步骤中_Py_Mangle
,因此函数永远没有机会调用__getattribute__('_classname__privatevarname')
。
例如,如果我们定义一个访问私有实例变量的简单外部添加函数__obj_val
:
def add_extern(self, value):
return self.__obj_val + value
并将其绑定到每个实例中,同时还在类定义中定义__init__
类似的实例方法add_intern
class TestClass(object):
def __init__(self, object_value):
self.__obj_val = object_value
self.add_extern = add_extern.__get__(self, TestClass)
def add_intern(self, value):
return self.__obj_val + value
那么内部方法将起作用,但外部绑定方法将引发异常:
>>> t = TestClass(0)
>>> t.add_intern(1)
1
>>> t.add_extern(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in add_extern
AttributeError: 'TestClass' object has no attribute '__obj_val'
POSTSCRIPT__getattribute__
:您可以通过重写为您进行修改来克服这个缺点:
class TestClass(object):
...
def __getattribute__(self, name):
try:
return super(TestClass, self).__getattribute__(name)
except AttributeError:
# mimic behavior of _Py_Mangle
if not name.startswith('__'): # only private attrs
raise
if name.endswith('__'): # don't mangle dunder attrs
raise
if '.' in name: # don't mangle for modules
raise
if not name.lstrip('_'): # don't mangle if just underscores
raise
mangled_name = '_{cls_name}{attr_name}'.format(
cls_name=self.__class__.__name__, attr_name=name)
return super(TestClass, self).__getattribute__(mangled_name)
但是,这并没有将变量留给外部调用者私有,这是我们不想要的。