2

The following piece of code:

class A:
    def __init__(self):
        self.__var = 123
    def getV(self):
        return self.__var
a = A()
a.__var = 10
print a.getVar(), a.__var

prints 123 10. Why does this behavior occur? I would expect a.getVar() to print out 10. Does the class internally interpret self.__var as self._A__var?

Abhi V
  • 684
  • 1
  • 4
  • 19
  • You're right. Read here: https://docs.python.org/2/tutorial/classes.html#private-variables-and-class-local-references – Reut Sharabani Oct 29 '19 at 06:49
  • This feature is called name mangeling and all attributes starting with double underscore are subject to it. – Klaus D. Oct 29 '19 at 06:50
  • Possible duplicate of [Why are Python's 'private' methods not actually private?](https://stackoverflow.com/questions/70528/why-are-pythons-private-methods-not-actually-private) – Energya Oct 29 '19 at 06:53

1 Answers1

3

The double underscore attributes in Python has a special effect, it does "name mangling" that is it converts the attribute __var to _A__var i.e. _<classname>__<attributename> at runtime.

In your example when you assign 10 to the attribute __var of a object, it is essentially creating a new attribute __var and not modifying the self.__var. This is because the self.__var is now _A__var due to name mangling.

This can be seen if you print the __dict__ of the a object:

class A:
    def __init__(self):
        self.__var = 123
    def getV(self):
        return self.__var
a = A()
print (a.__dict__)

>> {'_A__var': 123}

If you don't assign any value to __var and try to print it directly, it will result in an AttributeError:

class A:
    def __init__(self):
        self.__var = 123
    def getV(self):
        return self.__var
a = A()
print (a.__var)

>> AttributeError: 'A' object has no attribute '__var'

Now if you try to assign to the new mangled attribute name, you would get the right result (but this process is meant to prevent accidental usage of such variables):

class A:
    def __init__(self):
        self.__var = 123
    def getV(self):
        return self.__var
a = A()
a._A__var = 10
print (a.getV())

>> 10
Fullstack Guy
  • 14,425
  • 3
  • 18
  • 35