Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python name mangling and global variables

#global variable
_test__x=13

class test:
    def __init__(self,x):
        self.__x=x
    def rex(self):
        return __x

d = test(5)
print(d.rex())

if I run this code it will return 13 I know that the interpreter applied name mangling so the variable __x became _test__x but this is the same as the global variable.

i tried to use self._test__x but it did not work

How to access the __x variable declared in __init __.py but not the global variable?

like image 841
Khalid Nasser Avatar asked Oct 16 '22 03:10

Khalid Nasser


1 Answers

Name mangling happens anywhere in a class body according to the docs:

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 ... This transformation is independent of the syntactical context in which the identifier is used.

The tutorial example shows that the mangling happens to attributes within the class too.

But the real problem is that your code is confusing namespaces. The constructor you showed originally

def __init__(self, x):
    __x = x

creates a local variable _test__x, which gets discarded as soon as it completes.

To properly assign an instance attribute:

def __init__(self, x):
    self.__x = x

This will create an attribute whose name is actually _test__x.

If you actually want to assign the global:

def __init__(self, x):
    global __x
    __x = x

Or

def __init__(self, x):
    global _test__x
    __x = x

The getter needs to access the instance attribute just as the constructor needs to set it. The current version is accessing the global because the name _tesy__x does not exist in the local namespace:

def rex(self):
    return __x

To return an attribute, add the namespace:

def rex(self):
    return self.__x

All that being said, if you had a module-level attribute with a leading double underscore (which you just shouldn't do), you would have a very hard time accessing it in the class. You would have to go through globals, something like this:

globals()['__x']

Shameless plug of my question about that from a long time ago: How to access private variable of Python module from class.

Another fun fact: name mangling won't happen at all if your class name is all underscores. You can escape all your problems by naming classes _, __, ___, ____, etc.

like image 192
Mad Physicist Avatar answered Oct 18 '22 14:10

Mad Physicist