1

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

知道怎么了?

4

3 回答 3

4

你看到的是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 的一部分。检查 withdir只会提示您使用哪个名称,但由于它们是一个实现细节,它们可以在不通知的情况下更改。

不应该使用它来将属性“标记”为私有。python约定是以单个下划线开头的属性是私有的。

在一个相关主题上,在名称__something__的开头和结尾都带有双下划线的表单名称也被特殊处理。其中一些实现了特殊方法,因此您永远不应该使用这种标识符。

于 2013-02-26T22:10:04.170 回答
2

双下划线故意混淆变量名以使其半私有。有关更多详细信息,请参阅http://docs.python.org/2/tutorial/classes.html#private-variables-and-class-local-references

要解决此问题,请更改__Var1_Var1

于 2013-02-26T22:12:56.243 回答
1

Var1 前面的双下划线确实命名了重整。在运行时__Var1看起来像_MySubClass__Var1.

尝试用一个下划线重命名它 _Var1 。

名称修饰是 Python 创建某种私有变量的方式。这真的是为了防止命名空间冲突。

这里有一些细节

于 2013-02-26T22:12:44.280 回答