'Why is python mangling here

Why does this code fail if there is no cls. before __TEXT

__TEXT = "abcde"

print(__TEXT)
class aaa():
    @classmethod
    def bbb(cls):
        print(__TEXT)

aaa.bbb()

The output is:

abcde
Traceback (most recent call last):
  File "<string>", line 9, in <module>
  File "<string>", line 7, in bbb
NameError: name '_aaa__TEXT' is not defined

If you make __TEXT a class variable and try to reference it without the class prefix as follows:

class aaa():
    __TEXT = "abcde"
    @classmethod
    def bbb(cls):
        print(cls.__TEXT)
        print(__TEXT)

x = aaa()
x.bbb()

You get the same error but it doesn't make sense:

abcde
Traceback (most recent call last):
  File "<string>", line 10, in <module>
  File "<string>", line 7, in bbb
NameError: name '_aaa__TEXT' is not defined


Solution 1:[1]

Not quite sure if that was the error, but you can just make the function require a parameter text, that seems to work just fine. You need to give me more information though so I can try to help.

    __TEXT = "abcde"

    print(__TEXT)
    class aaa():
    @classmethod
    def bbb(self, __TEXT):
       print(__TEXT)

    aaa.bbb(__TEXT)

Solution 2:[2]

A double underscore prefix causes the Python interpreter to rewrite the attribute name in order to avoid naming conflicts in subclasses.

This is also called "name mangling." The interpreter changes the name of the variable in a way that makes it harder to create collisions when the class is extended later.

Reference docs: https://docs.python.org/3/tutorial/classes.html#private-variables

Solution 3:[3]

The Python Interpreter mangles variable-names with a double-underscore to avoid name clashes with variable-names defined by subclasses.

The goal behind this is almost equivalent to final variables in Java and non virtual in C++.

Take for instance:

class Human:
    def __init__(self):
        self.surname = 'Jeffrey'
        self._age = 22
        self.__id = 5

# Let's check the variables associated with this class
x = Human()
print(dir(x)) # gives: ['_Human__id', ..., '_age', 'name']

# Create a subclass 'Cook'

class Cook(Human):
    def __init__(self):
        Human.__init__(self)        
        self.__id = 25

y = Cook()
print(dir(y)) # gives: ['_Human__id', '_Cook__id', ..., '_age', 'name']

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Luis Valero
Solution 2 JamesRoberts
Solution 3 Bialomazur