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

Nitin Prakash
  • 328
  • 3
  • 15
  • 1
    `self.__x = ...` and `return self.__x`... right now it's just a local variable. No mangling involved. – Mad Physicist May 14 '20 at 03: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: https://bugs.python.org/issue27793 – bitomic May 14 '20 at 03:30
  • @bitomic. I'm not seeing the feature part from that thread. It's documented, but admittedly not behaving sensibly – Mad Physicist May 14 '20 at 03:33
  • Ok , I tried to but self.__x in __init __ and return self.__x in rex() and it works properly – Khalid Nasser May 14 '20 at 03:50
  • 1
    I'll write up an answer. This is one of the ugliest things in python, IMO – Mad Physicist May 14 '20 at 05:25
  • @MadPhysicist: This actually used to be [explicitly advertised in the tutorial](https://docs.python.org/release/1.5/tut/node67.html#SECTION0010600000000000000000): " This mangling is done without regard of the syntactic position of the identifier, so it can be used to define class-private instance and class variables, methods, as well as globals, and even to store instance variables private to this class on instances of *other* classes." – user2357112 May 14 '20 at 06:08
  • @user2357112supportsMonica. I'm pretty sure it still is. Mangling in general is a feature, yes. But some of the side effects are not. – Mad Physicist May 14 '20 at 06:11
  • @MadPhysicist: The existence of mangling is still advertised, but the tutorial no longer explicitly calls out the possibility of using it to create private globals or to create your-class-private variables on instances of other classes. – user2357112 May 14 '20 at 07:07

1 Answers1

3

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.

Mad Physicist
  • 107,652
  • 25
  • 181
  • 264