0

我得到这个回溯:

Traceback (most recent call last):
File "/home/amentis/Dropbox/Rexi/index.py", line 21, in application
ui = Console.Console()
File "/home/amentis/Dropbox/Rexi/UI/Console.py", line 9, in __init__
self.__window = Window.Window(self, 'consoleWindow')
File "/home/amentis/Dropbox/Rexi/RxAPI/RxGUI/Window.py", line 16, in __init__
self.__parent.add_child(self)
AttributeError: 'Window' object has no attribute '_Window__parent'

这是控制台类的一部分:

class Console(Screen.Screen):

    def __init__(self):
        super().__init__("REXI Console")
        self.__window = Window.Window(self, 'consoleWindow')

窗口类:

class Window(RxGUIObject.RxGUIObject):
    def __init__(self, parent, name):
        RxGUIObject.RxGUIObject.__init__(self, name, parent)
        self.__body = ""
        self.__javascript = ""
        self.__css = ""
        self.__parent.add_child(self)

和 RxGUIObject:

class RxGUIObject(RxObject.RxObject):
    def __init__(self, name, parent):
        RxObject.RxObject.__init__(self, name)
        self.__parent = parent
        self.__children = list

Window.__parent没有被创造或不存在,为什么?

4

2 回答 2

1

你刚刚偶然发现了 python 的名字 mangling。每个以双下划线开头并以最多一个尾随下划线结尾的属性,例如 your __parent,都被重命名为_ClassName__attributename.

>>> class A(object):
...     def __init__(self):
...             self.__a = 1
... 
>>> class B(A):
...     pass
... 
>>> b = B()
>>> b.__a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'B' object has no attribute '__a'
>>> b._A__a
1

为什么这样做?为了防止子类化时的属性冲突。特别是文档指出:

由于类私有成员有一个有效的用例(即避免名称与子类定义的名称发生名称冲突),因此对这种称为名称修饰的机制的支持有限。表单的任何标识符__spam(至少两个前导下划线,最多一个尾随下划线)在文本上替换为 _classname__spam,其中classname是去掉前导下划线的当前类名。只要它出现在类的定义中,就无需考虑标识符的句法位置,就可以完成这种修饰。

注意:名称修改并不意味着属性是私有的。如果您想将属性设置为“私有”,则约定是使用一个下划线:例如_parent. 如果您知道您的类将被子类化(通常),那么使用名称修饰来避免名称冲突可能是一个好主意。

请参阅Python 名称修改:如有疑问,该怎么办?决定是否使用它,但一般来说你不应该使用它。

另请注意,如果子类必须有权访问,__parent那么您绝对应该使用名称修饰,因为它的目的是避免子类访问该属性。在这种情况下,只需使用公共属性并记录它。或者,您可以使用带有名称修饰的私有属性和属性/某些方法将其作为隐藏的内部状态进行访问,但是对于简单的情况,这是一种矫枉过正的做法。

于 2013-11-05T07:44:46.267 回答
0

__parent是私有财产RxGUIObject

__double_leading_underscore:命名类属性时,调用名称修改(在类 FooBar 中,__boo 变为FooBar _boo;见下文)。

因此,您的__parent财产RxGUIObject将被视为_RxGUIObject__parent

为避免这种情况,请明确定义

def __init__(self, parent, name):
    RxGUIObject.RxGUIObject.__init__(self, name, parent)
    self.__body = ""
    self.__javascript = ""
    self.__css = ""
    self.__parent = parent
    self.__parent.add_child(self)
于 2013-11-05T07:45:12.503 回答