我有一个继承自Python中抽象类的类
class MyAbstractClass():
__Var1 = 0
def __init__(self):
pass
class MySubClass(MyAbstractClass):
def __init__(self):
MyAbstractClass.__init__(self)
def MyFunc(self):
print self.__Var1
出现以下错误:
AttributeError: MySubClass instance has no attribute '_MySubClass__Var1'
值得注意的是,这两个类是分开的文件。
我一直在搜索,大多数建议是将我的代码从使用“super()”更改为父级的显式名称。但是,我仍然在发现此错误。
有什么想法吗?
答案 0 :(得分:4)
您看到的是name mangling。以双下划线开头的名称以特殊方式处理,以避免在子类中发生名称冲突。
基本上,只要类中有__some_name
属性,它就会自动重命名为_YourClass__some_name
,以避免在继承时发生名称冲突。
您可以使用dir()
功能检查:
>>> class MyClass(object):
... __var = 1
...
>>> dir(MyClass)
['_MyClass__var', '__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
请注意列表不包含__var
但是包含_MyClass__var
。
修复很简单:不使用以双下划线开头的变量名。如果要将变量标记为私有,则约定是使用单个下划线。
我想再次强调,名称修改的主要目的是避免与子类的命名空间冲突:
>>> class MyClass(object):
... def __init__(self, val):
... self._value = val
...
>>> class MySubclass(object):
... def __init__(self, val):
... super(MyClass, self).__init__(val)
... self._value = val ** 2 #this hides the base class attribute!
...
请注意,如果基类来自第三方库,那么您无法知道定义了哪些私有属性,因为它们不是API的一部分。使用dir
进行检查只会提示您使用的名称,但由于它们是实施细节,因此可能会更改,恕不另行通知。
你不应该使用它来将属性“标记”为私有。 python 约定是以单个下划线开头的属性是私有的。
在相关主题上,还会特别处理名称开头和结尾都带有双下划线的__something__
形式的名称。其中一些实现了special methods因此你应该从不使用这种标识符。
答案 1 :(得分:2)
双下划线故意模糊变量名称以使其成为半私有。有关详细信息,请参阅http://docs.python.org/2/tutorial/classes.html#private-variables-and-class-local-references。
要解决此问题,请将__Var1
更改为_Var1
。
答案 2 :(得分:1)
Var1前面的双下划线确实名称错误。在运行时__Var1
看起来像_MySubClass__Var1
。
尝试使用单个下划线重命名_Var1。
名称修改是Python如何创建排序的私有变量。确实可以防止命名空间冲突。
此here
有一些细节