Sunday, 30 December 2018

Python: (_ & __) in variable names


Meaning of underscores (_ & __) in Python variable names:

Leading underscores in Python variable names (for example _foo and __foo) protect developers from naming conflicts. 

A single underscore in front of a variable name (prefix) is a hint that a variable is meant for internal use only. 

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

Double underscores are also called "dunders" in Python.


EXAMPLE:
========

class Test:
    def __init__(self):
        self.foo=11

        self._bar=23 #It is by convention,Name is treated private by a programmer

        self.__baz=42 #Called dunderBaz
                      


t=Test() #t is the object for the class Test
print(t)
print(dir(t))
print(t.foo)
print(t._bar)
#print(t.__baz)

Output:

<__main__.Test object at 0x103a9f4e0>
['_Test__baz', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', 
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', 
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__',
 '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 
'__weakref__', '_bar', 'foo']
11
23


NOTE:
=====
When we check the attributes on the object dir(t),when we look for foo,_bar,__baz in above 
list,we notice that foo and __bar appear same as as it is in class(Nothing Change),
when we notice __baz its _Test__baz (Python Interpretor Does this to prevent the subclasses, name mangling, i.e when Test class is inherited when they want to use the same name)
so 

print(t.foo)
print(t._bar) 

Prints proper values:
But if we do:
print(t.__baz)
it throws the error shown in below example. 
But prints if we do:
print(t._Test__baz)

USE it from CLASS It Self :self.__baz=42
It prevents subclass changing the attribute, its a prevention mechanism.


class Test:
    def __init__(self):
        self.foo=11

        self._bar=23

        self.__baz=42 #Name Mangling


t=Test()
# print(t)

# print(dir(t))

# print(t.foo)

# print(t._bar)

print(t.__baz)




Output:
Traceback (most recent call last):
  File "/Users/mbidsar/Desktop/Python/Python-Programs-Practise/core/Manish-Pgms/_and__.py",
 line 12, in <module>
    print(t.__baz)
AttributeError: 'Test' object has no attribute '

Taken from below Video Reference: