0

I am getting this traceback:

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'

Here is a portion of the Console class:

class Console(Screen.Screen):

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

Of the Window class:

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)

and the RxGUIObject:

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

Is Window.__parent not created or not existent and why?

Bakuriu
  • 98,325
  • 22
  • 197
  • 231
Ivan Bratoev
  • 235
  • 2
  • 13

2 Answers2

1

You just stumbled on python's name mangling. Every attribute that starts with a double underscore and ends with at most one trailing underscore, like your __parent, is renamed to _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

Why is this done? In order to prevent attributes clashes when subclassing. In particular the documentation states:

Since there is a valid use-case for class-private members (namely to avoid name clashes of names with names defined by subclasses), there is limited support for such a mechanism, called name mangling. Any identifier of the form __spam (at least two leading underscores, at most one trailing underscore) is textually replaced with _classname__spam, where classname is the current class name with leading underscore(s) stripped. This mangling is done without regard to the syntactic position of the identifier, as long as it occurs within the definition of a class.

Note: name mangling does not mean an attribute is private. If you want to make an attribute "private" the convention is to use one underscore: e.g. _parent. If you know that your class will be subclassed (often), then it may be a good idea to use name mangling to avoid name clashes.

Refer to Python name mangling: When in doubt, do what? to decide whether to use it or not, however in general you should not use it.

Also note that, if subclasses must have access to __parent then you definitely should not use name mangling, since its very aim is to avoid subclasses accessing the attribute. In such cases simply use a public attribute and document it. In alternative you can use a private attribute with name mangling and a property/some method to access it as hidden internal state, however for simple cases this is an overkill.

Community
  • 1
  • 1
Bakuriu
  • 98,325
  • 22
  • 197
  • 231
0

__parent is private property of RxGUIObject

__double_leading_underscore: when naming a class attribute, invokes name mangling (inside class FooBar, __boo becomes FooBar_boo; see below).

because of this your __parent property of RxGUIObject will be considered as _RxGUIObject__parent

To avoid this please define it explicetely

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)
oleg
  • 4,082
  • 16
  • 16