Skip to main content

Python 3 Part 10 - Object Oriented Programming in Python 3

Object Oriented Programming in Python 3

 

Table of content 

  1. Class
    • Types of variables
    • Types of methods
    • Namespaces
  2. Reusing code
    • Association
    • Inner class
    • Single level inheritance
    • Multi level inheritance
    • Multiple inheritance
  3. Constructor overloading
  4. Class overloading 
  5. Interfaces

Class

Class is blueprint or design. Class has attributes called data members and methods also known as behavior. By default the class data members and methods are public in Python class.

Syntax to define a class in python is

            class <ClassName>:
                <body>
                .
                .
                .

Below example is a class Computer. 

 
class Computer:
    # self is a reference to current object. Compulsory to have a self argument in instance method 
def config(self):
print("inside class")

obj = Computer()
obj.config()
 

Output

 
$ python3 class_example.py
inside class
$
 

There are 2 ways to access methods of class.

1. First method,  Computer.config(obj) 

2. Second method, obj.config()  

A class has a constructor that is used to initialize the data members of the class. Below example illustrates a Computer class with constructor __init__() method. It take a self as the first parameter followed by parameter list to be initialized.  processor and ram are parameter list.

These data members can be accessed using self.<attribute> (self dot attribute name) within the instance method.

 
class Computer:
def __init__(self,processor,ram): # constructor for Computer clas
self.processor = processor
self.ram = ram

def config(self):
print("Configurations are ",self.processor,self.ram) # access attributes by (self.attribute)

# while calling the constructor we only pass the data arguments.
# self argument us automatically passed
comp1 = Computer("i5",8)
comp2 = Computer("Ryzen 5",16)

comp1.config()
comp2.config()
 

Output

 
$ python3 class_contructor.py
Configurations are i5 8
Configurations are Ryzen 5 16
$ 
 

How to print address of object?

Using the inbuilt id() method we can find the address of the object.

 
$ python3
Python 3.9.0 (v3.9.0:9cf6752276, Oct 5 2020, 11:29:23)
[Clang 6.0 (clang-600.0.57)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> a = 10
>>> id(a)
140383553198672
>>> 
 

Types of variable

1. instance variables : are defined within instance method( methods that take self as argument)
2. class/static variables : variable declared outside all method but within class. They behave similar to static variable in java.

Types of methods

1. instance methods : Methods which deals with instance variable. It takes self as parameter.

 
class ClassWithInstanceMethod():
 
    # declare an instance method which takes self and variable as parameter 
def instance_method(self, variable):
self.variable = variable # store variable as instance variable
print(self.variable)

obj = ClassWithInstanceMethod()
obj.instance_method("Value")
 

Output

 
$ python3 class_with_inst_method.py
Value
$ 
 

2. class methods : Methods which deals with class variable. They have a @classmethod annotation and it take cls as the first parameter.

 
class ClassWithClassMethod:
class_variable = "This is class variable"

@classmethod
def class_method(cls): # cls is compulsary when we are define class method
print(cls.class_variable) # access the class variable using cls

obj = ClassWithClassMethod()
obj.class_method()
 

Output

 
$ python3 class_with_cls_method.py
This is class variable
$
 

3. static methods : Methods which has nothing to do with either instance or class variable. They have a @staticmethod annotation.

 
class ClassWithStaticMethod:
@staticmethod
def static_method():
print("This is static Method")

obj = ClassWithStaticMethod()
obj.static_method()
 

Output

 
$ python3 class_with_static_method.py
This is static Method
$
 

Namespace 

Namespaces is the area where we store variable and methods at the runtime. There are two types of namespace.

1. Class namespace : This namespace stores class variable and methods. Whenever we declare variable outside constructor which are class level variables and methods they are allocated space in class level namespace. 

2. Instance/object namespace : This namespace stores instance variable and methods. Whenever we declare instance variable and methods they are allocated to instamce namespace.

Reusing code

Associations : are a Has-A relationship. Example below a student has a laptop.

 
class Laptop:
def __init__(self,brand, processor):
self.brand = brand
self.processor = processor

def show(self):
print(self.brand,self.processor)

class Student:
def __init__(self,name,laptop):
self.name= name
self.laptop = laptop

def show(self):
print(self.name,self.laptop.brand,self.laptop.processor)

lap = Laptop("hp","i5")
lap.show()

s = Student("Ram",lap)
s.show()
 

Output

 
$ python3 has_a_relationship.py
hp i5
Ram hp i5
$ 
 

Inner class : are nested classes. It is used to group two or more classes. Suppose we have two classes remote and battery. Every remote needs a battery but battery without remote won’t be used. So, we make the Battery as an inner class to the Remote.

 
class Student:
def __init__(self,name,lap_brand):
self.name = name
self.lap = self.Laptop(lap_brand)
def show(self):
print(self.name,self.lap.brand)

# inner class
class Laptop:
def __init__(self,brand):
self.brand = brand

def show(self):
print(self.brand)

s = Student("Ram","hp")
s.show()

s.lap.show() # calling inner class method

lap1 = Student.Laptop("dell") # creating object of class outside outer class
lap1.show()
 

Output

 
$ python3 inner_class_example.py
Ram hp
hp
dell
$ 
 

Inheritance   

Another method of reusing the code is by inheritance. It is an example Is-A relationship. Example a Car is a Vehicle. This is a example of a single level inheritance. 

The syntax to inherit a class B in class A is as follows :

A(B) 

 The class A inherits class B.

class Vehicle:
def __init__(self,brand, fuel):
self.brand = brand
self.fuel = fuel

def service(self):
print(self.brand,"in servicing")

class Car(Vehicle):      # Car class inherits Parent Vehicle class
def __init__(self,model,brand,fuel):
self.model = model
super().__init__(brand,fuel) # calling constructor of super/parent class

c = Car("ipace","jaguar","power petrol")
c.service() # access parent class method through child object

Output

 
$ python3 single_inheritance.py
jaguar in servicing
$ 
 

Types of inheristance

1. Single level inheritance

When there is a single parent class inherited by a single child class.

 
             Vehicle (Super/parent class)
^
|
|
|
Car (Sub/child class)
 

2. Multi level inheritance 

When we have an hierarchy of class inheriting single level inheritance. Below example class C inherits class B ans class B inherits class A.

 
                A
^
|
|
B
^
|
|
C
 

3. Multiple inheritance

When a class inherits nultiple classes into single class. The syntax of multiple inheritance is as follows :

C(A,B)

 
            A B
^ ^
| |
---------
|
C
 


 
class A:
def feature(self):
print("feature-A")

class B:
def feature(self):
print("feature-B")

class C(A,B):
pass

c = C()
c.feature()
 

Output

 
$ python3 multiple_inheritance.py
feature-A
$ 
 

How is the method resolution done when multiple parent class has the same method. 

Let us create a new class D inheriting from B and A class as below.

 
class A:
def feature(self):
print("feature-A")

class B:
def feature(self):
print("feature-B")

class C(A,B):
pass

class D(B,A):
pass

c = C()
c.feature()

d = D()
d.feature()

Output

 
$ python3 method_resolution.py
feature-A
feature-B
$ 
 

As you can see the output for class D is calling the method from class B. Method resolution order is from left to right in inheriting classes. 

Method resolution order defines the order in which the base classes are searched when executing a method.

Constructor overloading

Constructor overloading is not possible in Python. If we try to overload a constructor it overrides the behavior of the constructor.

 
class Computer:

def __init__(self,processor):
self.processor = processor

#constructor
def __init__(self,processor,ram):
self.processor = processor
self.ram = ram

def config(self):
print("Configurations are ",self.processor,self.ram)

comp1 = Computer("i5")
comp2 = Computer("Ryzen 5",16)

comp1.config()
comp2.config()
 

 Output

 
$ python3 constructor_overloading.py
Traceback (most recent call last):
File "/Users/code/py/constructor_overloading.py", line 14, in <module>
comp1 = Computer("i5")
TypeError: __init__() missing 1 required positional argument: 'ram'
$ 
 

Class Overloading 

Python takes the latest definition of the class.

 
class Laptop:
def __init__(self,brand, processor):
self.brand = brand
self.processor = processor
def show(self,name):
print("hello",self.name)
def show(self):
print(self.brand,self.processor)

class Laptop:

def __init__(self,brand):
self.brand = brand
self.processor = processor
def show(self,name,processor):
print("hello",self.name)
def show(self):
print(self.brand,self.processor)

a = Laptop("hp","i5")
a.show()
a.show("ram")

Output

 
$ python3 class_overloading.py
Traceback (most recent call last):
File "/Users/code/py/class_overloading.py", line 24, in <module>
a = Laptop("hp","i5")
TypeError: __init__() takes 2 positional arguments but 3 were given
$ 
 

Note : As Python is an interpreted language it overrrides the first contructor definition and the second contructor is considered. Overloading of constructor, classes and method is not possible in Python. It takes the definition that comes later.

Interfaces

Is there Concept of interfaces in Python? No, there is no concept of interfaces in Python.

Thank you folks, if you like my post do check my other posts on Django with Python 3 and Ruby on Rails  on SWE crunch

Most viewed

Ruby on rails part 6 - Blocks , lambda, procs and closure

 Blocks , lambda, procs  and closure Table of content  1. Blocks 2. Lambda 3. Procs 4. Closure Blocks  Ruby blocks are little anonymous functions that can be passed into methods. Blocks are enclosed in a do-end statement or between brackets {} 
. Blocks can have multiple arguments
. The argument names are defined between two pipe | characters. Blocks are typically used with ‘each’ method which iterates over a list. Syntax of block using {} ['List of items'].each { | block arguments|  block body }  Syntax of block using do-end ['List of items'].each do | block arguments |      # block body end Example of block declared as do-end with each method.   [ 1 , 2 , 3 ].each do |num| puts num end     Output   $ ruby block_with_each.rb 1 2 3 $    Blocks can also be saved in variables or passed as argument to another function.   yield is a Ruby keyword that is used to call a block. When you use the yield keyword, the code inside the block will run. Example of saving a bl