Oops in Python
Oops in Python
Object-Oriented Programming.
Python is an “object-oriented programming language.” This means that almost all the code is implemented using a
special construct called classes.
Procedural programming is about writing procedures or methods that perform operations on the data, while object-
oriented programming is about creating objects that contain both data and methods.
Object-oriented programming has several advantages over procedural programming:
1. Object
2. Class
3. Inheritance
4. Polymorphism
5. Abstraction
6. Encapsulation
Classes and Objects
Classes and objects are the two main aspects of object-oriented programming.
When the individual objects are created, they inherit all the variables and methods from
the class.
Object − Objects have states and behaviors. Example: A dog has states - color, name, breed as
well as behavior such as wagging their tail, barking, eating. An object is an instance of a class.
Class − A class can be defined as a template/blueprint that describes the behavior/state that the
object of its type supports.
Methods − A method is basically a behavior. A class can contain many methods. It is in methods
where the logics are written, data is manipulated and all the actions are executed.
Instance Variables − Each object has its unique set of instance variables. An object's state is
created by the values assigned to these instance variables.
Major principles of object-oriented programming system are given below.
Object : The object is an entity that has state and behavior. It may be any real-world object like the mouse, keyboard, chair, table, pen, etc.
Class : A class is a blueprint for the objects. For example, Ram, Shyam, Steve, Rick are all objects so we can define a template (blueprint) class Human for these objects. The class can define the common attributes (properties) and behaviours of all the objects.
Method : The method is a function that is associated with an object. In Python, a method is not unique to class instances. Any object type can have methods.
Class
every class name in Python should start with a capital alphabet and the first alphabet of a multi-word name should be in the capital too. For eg : class MyFirstJavaClass
Every method defined in a Python class should be in lowercase and multi-word names are separated by an underscore. For eg : myMethodName()
Every instance variable defined in a Python class should be in lowercase and multi-word names are separated by an underscore.
Note :
• Python compiler doesn't throw a compile error if a class name starts with a lowercase
letter, but it's still better to follow the naming conventions defined in Python.
• Python is a case-sensitive language, hence a class containing two instance variables
with one named a and the other named A, are treated differently.
Class is a blueprint for the object to define a class keyword class is used : class classname
Object is instance of a class when class is defined only the description for the object is defined
therefore no memory/ storage is allocated for class.
Objname= classname() allocate memory ( instance means copy of the class with actual values)
Attributes(properties): attributes are the variables that belong to class they are always public can be
accessed using dot (.) operator.
Methods(behaviour): methods are functions defined inside the body of a class they are used to define the behaviour of an object
To delete object
del objectname
del p1
To create a class syntax
Class classname:
attributes
Methods
Eg class myclass:
x-=5
To create a object syntax
P1 =myclass ()
Print(p1.x)
Complete program
class myclass:
x-=5 attribute variable
P1 =myclass () object creation
Print(p1.x)
class myclass:
def _ _init_ _ (self ,name, age):
self.name = name
self.age = age
def myfun(self):
print(“name”, self.name)
print(“age”, self .age)
P1 = myclass( “sjc”,138)
P1.myfun()
Note : self is a reference parameter to the current instance of the class and is used to access variable
that belong to the class. It helps to differentiate between the methods and attribute of a class with
localyou can think of ‘self’ as the ‘this’ keyword which is used for the current object. It unhides the
current instance variable.’self’ mostly work like ‘this’ variable.
It has to be first parameter of any function in the class . It does not have to be named self it can be
anything
Class vect:
x=0.0
y=0.0
def set(self ,x,y): method definition
self.x= x
self.y =y
V= vect()
v.set(10,20) method call
Print(v.x,v.y)
we have not specified self word in the parameters of a static method, because self refers to the
currently executing object, while a static method is a class method and has got nothing to do with its
objects.
A static method can be accessed directly by using its class name and a dot operator Test.stat().
Class variable also known as static variable
instance variable also known as non static variable : are different for different object (every object has a copy of it)
class std:
stream =“cms”
def _ _ init_ _ (self , name , roll):
self.name = name
self.roll= roll
a= std(“xy” 10)
b=std(“ab”,20)
print (a.stream)
print(b.stream)
print (a.stream)
print(b.stream)
Constructor
•_ _ init _ _ function
• all classes have a function called _ _init _ _ function is always created and executed when a class is initiated
• it is a method /constructor in python this method is automatically called to allocate memory when a new object /instance of a class is
created all classes have __ init __ method
It is used to assign value to object that necessary to do when the object is created
For example
Class myclass: The constructor (init) is just another method. What is special about it, is
def _ _init_ _ (self ): that its called each time a new object is created.
self.name = “SJC” We create one object C with the line:
self.age = 123
P1 = myclass( )
Print (p1.name)
Print(p1.age)
In Python, internally, the __new__ is
the method that creates the object
constructors
Constructors are generally used for instantiating an object.
The task of constructors is to initialize(assign values) to the data members of the class when an object of
class is created. In Python the __init__() method is called the constructor and is always called when an
object is created.
Types of constructor
1. Default constructor : the default constructor is simple constructor which doesn’t accept any argument
its definition has only one argument which is a reference to the instance of the object
2. Parameterized constructor: constructor with parameter is known as parameterized constructor . The
parameterized constructor takes its first argument as a reference to the instance being constructor
known as self and other argument are provided by the programmer.
Default constructor
class bank:
def _ _init_ _(self):
self.balance =0
def withdraw(self , amount):
self.balance= amount
a= bank()
b=bank()
a.withdraw(100)
b.withdraw(200)
Print( “withdraw” : a.balance)
Print( “withdraw” : b.balance)
Parameterised constructor
Class rect():
def _ _ init _ _(self , bre , leng):
self .bre =bre
self. Leng =leng
def area(self):
return (self.bre * self.leng)
A=int(input(“enter breath of rectangle”)
B = int(input(“enter length of rectangle”)
obj = rect(A,B)
Print(“area”,obj.area())
Destructor
_ _ del _ _ method is known as a destructor method in python it called when all the reference of the object
have been deleted
Syntax def _ _ del _ _ (self)
Class std:
def _ _init _ _ (self):
print(“ object created”)
def _ _ del_ _ (self):
Print( “object destroyed”)
E=std()
del E
Inheritance : Important aspects of Object Oriented Programming. While programming, many a times, situations
arise where we have to write a few classes with some common features and some unique, class-specific features,
which include both variables and methods.
we can take out the common part and put it in a separate class, and make all the other classes inherit this class, to use
its methods and variables, hence reducing re-writing the common features in every class, again and again.
The class which inherits another class is generally known as the Child class, while the class which is inherited by
other classes is called as the Parent class.
Syntax of inheritance
class BaseClass:
Body of base class
class DerivedClass(BaseClass):
Body of derived class
Derived class inherits features from the base class, adding new features to it. This results into re-usability of code.
When a subclass(derived class) inherits a base class, it inherits all the members of superclass(base class), such
as :Instance variables of the base class. Methods of the base class.
Types of Inheritance
Single Inheritance - When a class is inheriting a single class.
class X:
a = 10
b = 20.6
def method_x(self):
return 'class X’
class Y(X):
i = 30
def method_y(self):
return 'class Y’
ob_y = Y()
print('a = : ', ob_y.a)
print('b = : ', ob_y.b)
print(ob_y.method_x())
print('y = : ', ob_y.i)
print(ob_y.method_y())
a = : 10
b = : 20.6
class X
y = : 30
class Y
multiple inheritance which inherits the feature of two classes(inheriting more than one
class at a time)
class X:
a = 10
b = 20.6
def method_x(self):
return 'class X’
class Y:
i = 20
def method_y(self):
return 'class Y’
class Z(X,Y):
j = 30
def method_z(self):
return 'class Z’
Z ob_z = Z()
print('a = : ', ob_z.a)
print('b = : ', ob_z.b)
print(ob_z.method_x())
print('i = : ', ob_z.i)
print(ob_z.method_y())
print('j = : ', ob_z.j) print(ob_z.method_z())
a = : 10 b = : 20.6 class X i = : 20 class Y j = : 30 class Z
multilevel inheritance : When a class inherits the features of multiple classes(inheriting one class at a time), it is known
as multilevel inheritance
class X:
x1 = 10
def get_x1(self):
return self.x1
class Y(X):
y1 = 20
def get_y1(self):
return self.y1
class Z(Y):
z1 = 30
def get_z1(self):
return z1
ob = Z()
print('x1 = : ',ob.x1)
print('x1 = : ',ob.get_x1())
print('y1 = : ',ob.y1)
print('y1 = : ',ob.get_y1())
print('z1 = : ',ob.z1)
print('z1 = : ',ob.get_z1())
Output
x1 = : 10 x1 = : 10 y1 = : 20 y1 = : 20 z1 = : 30 z1 = : 30
class Base1:
Single Inheritance
pass
class Base2(Base1) :
pass
class Base1:
pass
class Base2(Base1) :
Multilevel Inheritance
pass
Class Base3(Base2):
pass
class Base1:
pass
class Base2: Multiple Inheritance
pass
class MultiDerived(Base1, Base2):
pass
The super() function in Python makes class inheritance more manageable and extensible. The function returns a
temporary object that allows reference to a parent class by the keyword super.
class MyParentClass():
def __init__(self):
pass
class SubClass(MyParentClass):
def __init__(self):
super().__init__()
class A(object): class A(object):
def __init__(self): def __init__(self):
print(“Inside A inheritance”) print(‘Inside A inheritance’)
In most of the object-oriented languages access modifiers are used to limit the access to the variables and functions of a
class.
Access modifiers is used to protect the data from unauthorized access as well as protecting it from getting manipulated.
When inheritance is implemented there is a huge risk for the data to get destroyed(manipulated) due to transfer of
unwanted data from the parent class to the child class. Therefore, it is very important to provide the right access
modifiers for different data members and member functions depending upon the requirements.
Most programming languages has three forms of access modifiers, which are Public, Protected and Private in a class.
Python doesn't have any mechanism that effectively restricts access to any instance variable or method. Python
prescribes a convention of prefixing the name of the variable/method with single or double underscore to emulate the
behaviour of protected and private access specifiers.
Protected : to make an instance variable protected is to add a prefix _ (single underscore) to it. This effectively prevents
it to be accessed, unless it is from within a sub-class.
class std:
def _ _init_ _(self, name, fee):
self._name=name
self._fee=fee
Private: to make an instance variable private a double underscore _ _ prefixed to a variable makes it private. These
members are only accessible from within the class. No outside class Access is allowed.
class std:
def _ _init_ _(self, name, fee):
self._ _name=name
self._ _ fee=fee
Protected
Protected variables and methods are very similar to private ones. You probably won't use
protected variables or methods very often, but it's still worth knowing what they are. A
variable that is protected can only be accessed by its own class and any classes derived
from it. That is more a topic for later, but just be aware that if you are using a class as the
basis of another one, protected variables may be a good option. Protected variables begin
with a single underscore.
# define parent class Company
class Company:
def __init__(self, name, proj):
self.name = name # name(name of company) is public
self._proj = proj # proj(current project) is protected
Polymorphism is taken from the Greek words Poly (many) and morphism (forms). It
means that the same function name can be used for different types. This makes
programming more intuitive and easier.
We know that the + operator is used extensively in Python programs. But, it does not have
a single usage.
For integer data types, + operator is used to perform arithmetic addition operation.
num1 = 1
num2 = 2
print(num1+num2)
Method Overloading:
Method Overloading is the class having methods that are the same name with different arguments.
Arguments different will be based on a number of arguments and types of arguments.
It is used in a single class.
It is also used to write the code clarity as well as reduce complexity.
Method Overriding:
Method Overriding is the method having the same name with the same arguments.
It is implemented with inheritance also.
It mostly used for memory reducing processes.
Polymorphism with Inheritance
Polymorphism in python defines methods in the child class that have the same name as the methods in the parent
class. In inheritance, the child class inherits the methods from the parent class. Also, it is possible to modify a
method in a child class that it has inherited from the parent class.
This is mostly used in cases where the method inherited from the parent class doesn’t fit the child class. This
process of re-implementing a method in the child class is known as Method Overriding.
For example,
class OverloadDemo:
def method(self, a):
print(a)
obj = OverloadDemo()
obj.method(5)
obj.method(‘sjc’)
obj.method(10.2)
Same method works for 3 different data types. Thus, you cannot define two methods with the
same name and same number of arguments
Advantages of Method Overloading in Python.
•Normally methods are used to reduce complexity. Method overloading is even it reduce more complexity in the
program also improves the clarity of code.
•It is also used for reusability.
It has some disadvantages also when creating more confusion during the inheritance concepts.
class OverloadingDemo {
methodOne(int a) {
Print(a)
}
methodOne(String a) {
Print(a)
}
methodOne(int a, String b) { }
methodOne(double a) {}
}
when the arguments have different types but one might ask that overloading can also be performed when the
number of arguments are different. This is also not possible because python treats all the methods with the
same name as one method irrespective of the number of arguments. If there are more than one methods with
same name then last method definition will over write the other even if they have different number of
arguments, that is, python will only consider and the last method as if this is the only method present in the
class
class OverloadDemo:
def method(self):
print("No argument")
def method(self, a):
print("One argument")
def method(self,a, b):
print("Two arguments")
obj = OverloadDemo()
obj.method(10)
This is because the last method over writes the other two methods and only one method is
present in the class which accepts two arguments but we supplied only 1 argument while
calling. If the number of arguments of the last method do not match the number of arguments
supplied while calling the method, it will be an error.
class OverloadDemo:
def default_arguments(self, a=‘sjc', b='the website’):
print(a)
print(b)
obj = OverloadDemo()
obj.default_arguments('learning', 'python')
Operator Overloading
Python operators work for built-in classes. But the same operator behaves differently
with different types. For example, the + operator will perform arithmetic addition on two
numbers, merge two lists, or concatenate two strings
This feature in Python that allows the same operator to have different meaning according
to the context is called operator overloading.
For example
• + operator for different purposes.
print(1 + 2)
• concatenate two strings
print(“python"+"For")
• Product two numbers
print(3 * 4)
• Repeat the String
print("Geeks"*4)
class point:
def __init__(self,x,y):
self.x=x
self.y=x
p1=point(1,3)
p2=point(2,3)
p3=p1+p2
print(p3)
throws an error, because compiler don’t know how to add two objects. So we define a method for an
operator and that process is called operator overloading.
We can overload all existing operators but we can’t create a new operator.
To perform operator overloading, Python provides some special function or magic function that is
automatically invoked when it is associated with that particular operator.
For example, when we use + operator, the magic method __add__ is automatically invoked in which the
operation for + operator is defined.
Overloading binary + operator in Python :
When we use an operator on user defined data types then automatically a special function or magic function
associated with that operator is invoked.
Changing the behavior of operator is as simple as changing the behavior of method or function.
You define methods in your class and operators work according to that behavior defined in methods.
# Python Program illustrate how
# to overload an binary + operator
class A:
def __init__(self, a):
self.a = a
Create a Module
To create a module, create a Python file with a .py extension.
Call a Module
Modules created with a .py extension can be used in another Python source file,
using the import statement.
Built-in Modules
There are several built-in modules in Python, which you can import whenever you like.
First module
def SayHello(name):
print("Hello " + name)
return
Second module
def sum(x,y):
return x+y
def average(x,y):
return (x+y)/2
def power(x,y):
return x**y
Create test.py in the MyApp folder to test mypackage.
_init__.py
The package folder contains a special file called __init__.py, which stores the package's
content. It serves two purposes:
1.The Python interpreter recognizes a folder as the package if it contains __init__.py file.
2.__init__.py exposes specified resources from its modules to be imported.
3.An empty __init__.py file makes all functions from above modules available when this
package is imported.
What’s Inheritance?
Inheritance models what is called an is a relationship. This means that when you
have a Derived class that inherits from a Base class, you created a relationship
where Derived is a specialized version of Base.
What’s Composition?
Composition is a concept that models a has a relationship. It enables creating
complex types by combining objects of other types
Class that references to one or more object of other classes as an instance variable
By using class name or by creating the object we can access the member of one
class inside another class
Inheritance is used where a class wants to derive the nature of parent class and then
modify or extend the functionality of it. Inheritance will extend the functionality with
extra features allows overriding of methods
in the case of Composition, we can only use that class we can not modify or extend
the functionality of it. It will not provide extra features. Thus, when one needs to use
the class as it without any modification, the composition is recommended and when
one needs to change the behavior of the method in another class, then inheritance is
recommended.
Aggregation
Not to confuse, aggregation is a form of composition where objects are loosely coupled. There are not any
objects or classes owns another object. It just creates a reference. It means if you destroy the container, the
content still exists.
Aggregation vs composition
composition : if you delete the container object then all of its contents objects are also deleted.
Aggregation is a week form of composition. If you delete the container object contents objects can
live without container object.
lambda function
A lambda function is a small anonymous function which returns an object.
The object returned by lambda is usually assigned to a variable or used as a part of other bigger functions.
Instead of the conventional def keyword used for creating functions, a lambda function is defined by using
the lambda keyword. The structure of lambda can be seen below:
The lambda function can have any number of arguments but there's always a single expression
after the : symbol. When this function is called, the expression is its return value.
square = lambda n : n*n
num = square(5)
print num
sub = lambda x, y : x-y
print(sub(5, 3))
it cannot substitute a function whose body may have conditionals, loops etc.
A lambda is much more readable than a full function since it can be written in-
line. Hence, it is a good practice to use lambdas when the function expression is
small.
The beauty of lambda functions lies in the fact that they return function objects
Static Methods
Static methods are methods that are related to a class but do not need to access any class-specific data.
There is no need to instantiate an instance because we can simply call this method. Static methods are
great for utility functions. They are totally self-contained and only work with data passed in as arguments.
This method is bound to the class but not to the object of the class.
This method can not access or modify class state.
This method is defined inside a class using @staticmethod decorator.
It does not receive any implicit first argument, neither self nor cls.
This method returns a static method of the function
Class Methods In Python
Class methods are methods that are related to a class and have access to all class-specific data. It uses
@classmethod, a built-in function decorator that gets evaluated after the function is defined. It returns
a class method function. It receives the cls parameter instead of self as the implicit first argument.
This method is also bound to the class but not to the object of the class.
This method can access the state of the class, therefore it can modify the class state that will be
applicable to all the instances.
This method is defined inside a class using @classmethod decorator.
It takes cls as a parameter that points to the class and not to the instance of the object.