6
#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?

8
  • 1
    self.__x = ... and return self.__x... right now it's just a local variable. No mangling involved. Commented May 14, 2020 at 3:29
  • I think is not something you could do (at least not easily), and is not a bug but a feature (it is actually part of the specification, apparently). See: bugs.python.org/issue27793 Commented May 14, 2020 at 3:30
  • @bitomic. I'm not seeing the feature part from that thread. It's documented, but admittedly not behaving sensibly Commented May 14, 2020 at 3:33
  • Ok , I tried to but self.__x in __init __ and return self.__x in rex() and it works properly Commented May 14, 2020 at 3:50
  • 1
    I'll write up an answer. This is one of the ugliest things in python, IMO Commented May 14, 2020 at 5:25

1 Answer 1

4

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 _test__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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.