Python继承的未知AttributeError

时间:2013-02-26 22:08:16

标签: python inheritance

我有一个继承自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()”更改为父级的显式名称。但是,我仍然在发现此错误。

有什么想法吗?

3 个答案:

答案 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

有一些细节