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:





Wednesday 19 December 2018

Python OOPS Basic Examples


Class, Objects and Class Methods
#Object: is collection of data and its funcationality:Eg:House
#Class:Blue Print/Template of object ,using class we can create many objects:Eg: Blueprint/FLoor plan for house,using sketch many houses can be built,
#similary using class we can create many object

#Simple Creation of Class and Object
class Person:
   
pass

#main

p=Person() #creation of object
print(p)
#<__main__.Person object at 0x10433a588>
#Means object beloning to class person is created and saved in memory location.



#Class Method
#Methods belonging to class
class Person:
#Self is 1 st parameter of class method arguments.
   
def name(self):
       
print("Manish")

person1=Person()
person1.name()


#Init Method
#Init will differenticate between Instance Variable and Local Variable
#Instace Variable is a Variable that belongs to a object
#Local Variable is a Variable
#self.name is a instance variable
#name :is a local variable
class Person:
#Used to Initailize the object
   
def __init__(self,name):
       
self.name = name

   
def display(self):
       
print("Hello",self.name)


person1=Person(
"Manish")
person1.display()

Class and Instance Variables
#Variables Belonging to Object or Instance is called Instance Variable
#In Below example,roolno and name are instance variables.
#Varible beloging to a class is a class variable,Single variable belong to all the object in a class.
#In Below example ,clg is a class varaible and same to all the students(Objects)


class Student:
    clg=
"BIT"  #CLASS VARIABLE

   
def __init__(self,rollno,name):
       
self.rollno = rollno #rollno and name are instance variable
       
self.name = name

   
def display(self):
       
print("Student Name:", self.name)
       
print("Student Rollno: ",self.rollno)
       
print("College",Student.clg)

student1=Student(
"01",'RAM')
student2=Student(
"02",'MOHAN')
student3=Student(
"03",'RAJU')
student1.display()
student2.display()
student3.display()

Inheritance
#Fundamental Features for OOP:1->Inheritance,2->Encapsulation,3->Polymorphism
#Inheritance enable us to define a class that takes all the functionality from parent class and allows us to add more.
# Inheritance is a powerful feature in object oriented programming.
#It refers to defining a new class with little or no modification to an existing class.
# The new class is called derived (or child) class and the one from which it inherits is called the base (or parent) class.

#Since eating is common property of Animals,Dog class is derived the method eating.

class Animal:#Base Class
   
def eating(self):
       
print("This Animal Eats")

class Dog(Animal):#Inheritance,Child Class
   
def bark(self):
       
print("Dog Barks")

d=Dog()
d.eating()
#this method is derived from Animal class
d.bark()

Multiple and Multilevel Inheritance
#Multlevel Inheritcance

#Base Class
class Person:
   
def display(self):
       
print("This is Base Class Display Function")

#Derived Class1
class Employee(Person):
   
def display1(self):
       
print("This is Derived Class1 Display Function")

#Derived Class2
class Programmer(Employee):
   
def display2(self):
       
print("This is Derived Class2 Display Function")


p1=Programmer()
p1.display()
p1.display1()
p1.display2()



#Multiple Inheritance

#Base Class1
class land_animal():
   
def display_land(self):
       
print("This Animal Lives on Land")

#Base Class2
class water_animal():
   
def display_water(self):
       
print("This Animal Lives on Water")

#Derived class
class frog(land_animal,water_animal):
   
pass

f1=frog()
f1.display_land()
f1.display_water()

Method Overriding
#Method Overriding

class A:
   
def display(self):
       
print("Display Class A")

class B(A):
   
pass

b=B()
b.display()

#Method Overriding
#Here the display function is common but the derived class display is overridden with base class display.
class A:
   
def display(self):
       
print("Display Class A")

class B(A):
   
def display(self):
       
print("Display Class B")

b=B()
b.display()


Encapsulation:
#In an object oriented python program, you can restrict access to methods and variables.
# This can prevent the data from being modified by accident and is known as encapsulation.
# There are two type access specifiers one is private and another is public.
# Public methods and variables can be accessible outside the class also.
# But we cant access private methods outside the class and private variables can be modified only inside the class.

#Objects can hold crucial data for your application and you do not want that data to be changeable from anywhere in the code.
#Encapsulation is helpful in this case.Two underscore at the beginning of method or variable indicates that it is private.


class Car:
   
def __init__(self):
       
self.__update_software() #Double Underscore Indicates its a Private Method to the Class

   
def drive(self):
       
print("Car Driving")
   
def __update_software(self):
       
print("Updating Software")

car1=Car()
#
car1.drive()

#Private Methods Cannot be accessed outside the class
#so car1.__update_software gives"AttributeError: 'Car' object has no attribute '__update_software'"
class Car:
   
def drive(self):
       
print("Car Driving")
   
def __update_software(self):
       
print("Updating Software")

car1=Car()
#
car1.__update_software


#Private Varible:It can be modified inside class methods.Cannot be modified outside the class.
class Car:
    __maxspeed=
0
   
__name=""
   
def __init__(self):
       
self.__maxspeed=200
       
self.__name="BMW"

   
def drive(self):
       
print("Car can be Driven")
       
print(self.__maxspeed)

   
def set_speed(self,speed):
       
self.__maxspeed=speed
       
print(self.__maxspeed)

c1=Car()
c1.drive()
c1.set_speed(
400)


#Trying to Modify the Private Variable Outside the Class

class Car:
    __maxspeed=
0
   
__name=""
   
def __init__(self):
       
self.__maxspeed=200
       
self.__name="BMW"

   
def drive(self):
       
print("Car can be Driven")
       
print(self.__maxspeed)


c1=Car()
c1.drive()
c1.__maxspeed=
400
c1.drive()

#Max Speed Value is not modified from outside the class.
#Car can be Driven
#200
#Car can be Driven
#200


Polymorphism:
#Polymorphism is the ability of an object to adapt the code to the type of the data it is processing.
#Here poly means many and morphi means forms.In Python polymorphism is one of the key concepts and we can say that it is a built-in feature.
#polymorphism helps us to describe an action regardless of the type of objects.
#

class Dog:
   
def sound(self):
       
print("Dog Barks")

class Cat:
   
def sound(self):
       
print("Cat Meows")

def makesound(animaltype):
    animaltype.sound()


#sound method is called based on the object type
catobj=Cat()
dogobj=Dog()
makesound(catobj)
makesound(dogobj)