-3

I've read all the similar posts regarding this topic but none that I found related to my problem in a way that helped me figure out what was happening.

class A:
    def __init__(self, value):
        self.__value = value
        self.__conn = httpsconnection # Specifics don't matter

class B(A):
    def __init__(self, id, type, value):
        super().__init__(value)
        self.data = self.__create_sub_class(id, type)

    def __create_sub_class(self, id, type):
        self.__conn.request(...)
        ...
        return data

class C(B):
    def __init__(self, id, value):
        super().__init__(id, externalVariable, value)

The error I am getting is AttributeError: 'C' object has no attribute '_B__conn'

Shouldn't class C inherit the variable from B which inherited it from A?

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Spedwards
  • 4,167
  • 16
  • 49
  • 106

1 Answers1

1

Do not use leading double-underscore names if you want to use those names in subclasses. The __name is explicitly designed to make the name class private, that is, only useful for the exact class. The idea is that you can use such names in a framework without then limiting what names subclasses can use.

Such names are mangled at compile time; they have _ClassName prefixed (with the current class name). Simply use single underscore names if you want to signal that a name is internal (Python has no actual privacy model, names are always accessible):

class A:
    def __init__(self, value):
        self._value = value
        self._conn = httpsconnection # Specifics don't matter

class B(A):
    def __init__(self, id, type, value):
        super().__init__(value)
        self.data = self._create_sub_class(id, type)

    def _create_sub_class(self, id, type):
        self._conn.request(...)
        ...
        return data

See Reserved classes of identifiers in the lexical analysis documentation:

__*
Class-private names. Names in this category, when used within the context of a class definition, are re-written to use a mangled form to help avoid name clashes between “private” attributes of base and derived classes.

and the referenced documentation on names:

Private name mangling: When an identifier that textually occurs in a class definition begins with two or more underscore characters and does not end in two or more underscores, it is considered a private name of that class. Private names are transformed to a longer form before code is generated for them. The transformation inserts the class name, with leading underscores removed and a single underscore inserted, in front of the name. For example, the identifier __spam occurring in a class named Ham will be transformed to _Ham__spam. This transformation is independent of the syntactical context in which the identifier is used.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • Thank you. I didn't know about the whole name-mangling. I don't know why but I've always preferred using double underscores over single. I guess that'll have to change now. – Spedwards Sep 03 '17 at 11:59