Classes and Objects;
Inheritance
Namespace
Namespace are used to ensure that any name used in program is
unique and do not have any conflict.
A namespace is a container for names (like variables, functions, and
classes), preventing naming conflicts and organizing code.
These are stored as dictionaries.
These map names to objects.
Python creates namespaces dynamically, and they can be modified
at runtime.
2
Namespace
Namespaces are created at different moments and have different lifetimes.
1. Built-in Namespace- Contains all built in functions and classes e.g. len(),
print().
It is created when the python interpreter starts and these namespaces are never
deleted.
3
Contains all built-in functions and classes (e.g., len(), print(), int, str).
Namespace
2. Global Namespace-
These consists of names given on top of program.
The global namespaces are created when the module definition is read-
in and deleted when the interpreter quits.
3. Local Namespace-
Created when a function is called.
The local namespace for a function is created when the function is
called, and deleted when the function returns or raises an exception that
isn’t handled in the function.
4
Scope
5
Local Scope
1. Local Scope
The Variables which are defined in the function are a local scope of the
variable. These variables are defined in the function body.
num=0
def demo():
#print(num) Local Variable
num=1
print("The Number is:",num)
demo()
Output:
6
Global Scope
2. Global Scope
The Variable which can be read from anywhere in the program is
known as a global scope. These variables can be accessed inside and
outside the function. When we want to use the same variable in the rest
of the program, we declare it as global.
In the following Example 1, we have declared a variable Str, which is
outside the function. The function demo is called, and it prints the value
of variable Str. To use a global variable inside a function, there is no
need to use the global keyword.
7
Global Scope
Example 1 Example 2
def demo(): def demo():
print(Str) print(Str)
Str = "You are smart"
# Global print(Str)
Str = "You are clever"
demo() # Global scope
Str = "You are Clever"
Output: demo()
print(Str)
Output:
8
Global Scope and Global Keyword
In the above Example, 2, try to change the value of the global variable
Str inside the function. It will raise an exception.
To modify or assign a new value to the variable inside the function,
one must write global.
If you want to tell a python interpreter that you want to use a global
variable, then the keyword “global” is used.
If it has not been declared as global, then python treats that variable as
local if it is created or modified inside the function.
9
Global Scope and Global Keyword
def demo():
global Str
print(Str)
Str = "You are smart"
print(Str)
# Global scope
Str = "You are Clever"
demo()
print(Str)
Output:
10
Non Local or Enclosing Scope
3. Non Local or Enclosing Scope
Nonlocal Variable is the variable that is defined in the nested function.
It means the variable can be neither in the local scope nor in the global
scope.
To create a nonlocal variable nonlocal keyword is used.
Enclosing Scope: It specifically targets the scope of the
immediate parent function, not the global (module) scope.
11
Non Local or Enclosing Scope
“””Without nonlocal: inner creates a
new variable
With nonlocal: inner modifies outer
variable””
12
Non Local or Enclosing Scope
When to use NonLocal
State Management in Closures:
•Useful when you want to maintain a state across multiple calls to a function.
Avoid Using Global Variables:
•It helps in limiting variable scope without making it global, promoting cleaner code.
13
Non Local or Enclosing Scope
Example 1: Modifying a Counter Using nonlocal
def outer_function():
count = 0
Declare that a variable refers to a def inner_function():
previously bound variable in the nonlocal count
nearest enclosing scope (but not count += 1
the global scope). print(f"Count: {count}")
inner_function()
inner_function()
outer_function()
14
4. Built-in Scope
If a Variable is not defined in local, Enclosed or global scope, then
python looks for it in the built-in scope.
Example, from math module pi is imported, and the value of pi is not
defined in global, local and enclosed. Python then looks for the pi value
in the built-in scope and prints the value. Hence the name which is
already present in the built-in scope should not be used as an identifier.
# Built-in Scope
from math import pi
# pi = 'Not defined in global pi'
def func_outer():
# pi = 'Not defined in outer pi'
def inner():
# pi = 'not defined in inner pi'
print(pi)
inner()
15
func_outer()
OOP, Defining a Class
• Python was built as a procedural language
– OOP exists and works fine, but feels a bit more "tacked on"
– Java probably does classes better than Python.
• A class is a code template for creating objects and is created by
the keyword class.
• Objects have member variables and have behaviour associated
with them. An object is created using the constructor of the
class. This object will then be called the instance of the class.
16
OOP, Defining a Class
• Declaring a class:
class name:
statements
A class by itself is of no use unless there is some functionality
associated with it.
Functionalities are defined by setting attributes like data
members (class variables and instance variables) and
functions related to those attributes. Those functions are
called methods.
17
Important Terms
• Instance − An individual object of a certain class. An object
“Circle1” that belongs to a class “Circle”, for example, is an instance
of the class Circle.
• Instantiation − The creation of an instance of a class.
• Method − A special kind of function that is defined in a class
definition.
• Object − A unique instance of a data structure that's defined by its
class. An object comprises both data members (class variables and
instance variables) and methods.
18
Important Terms
• Class variable − A variable that is shared by all instances of a class.
Class variables are defined within a class but outside any of the
class's methods. Class variables are not used as frequently as
instance variables are.
• Data member − A class variable or instance variable that holds data
associated with a class and its objects.
• Instance variable − A variable that is defined inside a method and
belongs only to the current instance of a class.
19
Difference Class Variable and Instance
Variable
• Whenever we expect that the variables are about to be consistent
across instances, or whenever we have to initialize a variable, then
that variable can be defined at the class level.
• Whenever we look forward to the variables that will alter
significantly across instances, then that variable can be defined at the
instance level.
20
Important Terms
• Constructor- The constructor is a method that is called when an
object is created. This method is defined in the class and can be
used to initialize basic variables.
If you create four objects, the class constructor is called four
times. Every class has a constructor, but its not required to
explicitly define it.
• __init__()- The first method __init__() is a special method, which
is called class constructor or initialization method that Python
calls when you create a new instance of this class.
21
OOP, Defining a Class
Attributes:
You can define the following class with the name Snake. This
class will have an attribute name.
>>> class Snake:
... name = "python" # set an attribute `name` of the class
Class Variable
Methods:
Once there are attributes that “belong” to the class, you can
define functions that will access the class attribute. These
functions are called methods. When you define
methods, you will need to always provide the first argument
to the method with a self keyword.
Python does not really have encapsulation or
private fields. To create private members start
them with underscore e.g. _name_, _age_22
Attributes/Data
Example:
class Point:
“This is Point class”
x = 0 [Link]
y = 0 1 class Point:
# main 2 x = 0
p1 = Point() 3 y = 0
p1.x = 2
p1.y = -5
print(p1.__doc__)
– can be declared directly inside class (as shown here)
or in constructors (more common)
– There are also special attributes in it that begins with double
underscores __. For ex: __doc__ gives us the docstring of that
class. Here, it is “This is Point class”
23
Methods
def name(self, parameter, ..., parameter):
statements
– self must be the first parameter to any object method
• represents the "implicit parameter" (this in Java)
– must access the object's fields through the self reference
class Point: Instance variables
def translate(self, dx, dy):
self.x += dx
self.y += dy
... 24
The self Parameter
The self parameter is a reference to the current instance of
the class, and is used to access variables that belongs to
the class.
It can be named otherwise but we highly recommend to follow
the convention.
Whenever a method is called using an object, address of the
object gets passed to the method implicitly. This address is
collected by the method in a variable called self.
25
"Implicit" Parameter (self)
• Java: this, implicit
public void translate(int dx, int dy) {
x += dx; // this.x += dx;
y += dy; // this.y += dy;
}
• Python: self, explicit
def translate(self, dx, dy):
self.x += dx
self.y += dy
26
Constructors
def __init__(self, parameter, ..., parameter):
statements
– a constructor is a special method with the name __init__.
– It does not return any value.
– Example:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
...
27
Calling Methods
• A client can call the methods of an object in two ways:
– (the value of self can be an implicit or explicit parameter)
1) [Link](parameters)
or
2) [Link](object, parameters)
• Example:
p = Point(3, -4)
[Link](1, 5)
[Link](p, 1, 5)
28
Calling Methods
• Python uses special methods to enhance the functionality
of classes.
• Most of them work in the background and are called
automatically when needed by the program. You cannot
call them explicitly.
• For instance, when you create a new object, Python
automatically calls the __new__ method, which in turn
calls the __init__ method. The __str__ method is called
when you print() an object.
29
Calling Methods
class Dog:
def __init__(self,dogBreed,dogEyeColor):
[Link] = dogBreed
[Link] = dogEyeColor
Tomita = Dog("Fox Terrier","brown")
Here, the __init__ method uses the keyword self to assign
the values passed as arguments to the object attributes
[Link] and [Link].
30
Access Object Attributes
To access an attribute of new object, you can use the dot (.)
notation to get the value you need.
Example:
print("This dog is a", [Link], "and its eyes are",
[Link])
Delete Object Properties/Attributes
You can delete properties on objects by using the del
keyword:
del [Link]
31
Example
class Person:
def __init__(self, name, age):
[Link] = name
[Link] = age
def myfunc(self):
print("Hello my name is " + [Link])
p1 = Person("John", 36)
del [Link]
print([Link])
32
The pass Statement
class definitions cannot be empty, but if you for some
reason have a class definition with no content, put in
the pass statement to avoid getting an error.
Example
class Person:
pass
• It results in no operation (NOP).
• The pass statement is used as a placeholder for future code.
33
Python built-in class functions
S Function Description
N
1 getattr(obj,name It is used to access the attribute of
,default) the object.
2 setattr(obj, It is used to set a particular value to
name,value) the specific attribute of an object.
3 delattr(obj, It is used to delete a specific
name) attribute.
4 hasattr(obj, It returns true if the object contains
name) some specific attribute.
34
Built-in class attributes
S Attribute Description
N
1 __dict__ It provides the dictionary containing the information
about the class namespace.
2 __doc__ It contains a string which has the class
documentation
3 __name__ It is used to access the class name.
4 __module__ It is used to access the module in which, this class is
defined.
5 __bases__ It contains a tuple including all base classes.
35
Exercise
1. Write a Python program to create a Vehicle class with
max_speed and mileage instance attributes.
2. Create a Bus child class that inherits from the Vehicle class. The
default fare charge of any vehicle is seating capacity * 100. If
Vehicle is Bus instance, we need to add an extra 10% on full fare
as a maintenance charge. So total fare for bus instance will
become the final amount = total fare + 10% of the total fare.
Note: The bus seating capacity is 50.
3. Show the use of built in class functions getattr, setattr, delattr and
hasattr.
36
Exercise
class Vehicle:
def __init__(self, name, mileage, capacity):
[Link] = name
[Link] = mileage
[Link] = capacity
def fare(self):
return [Link] * 100
class Bus(Vehicle):
pass
School_bus = Bus("School Volvo", 12, 50)
print("Total Bus fare is:", School_bus.fare())
37
Using a Class
import class
point_main.py
1 from Point import *
2
3 # main
4 p1 = Point()
5 p1.x = 7
6 p1.y = -3
7 ...
8
9 # Python objects are dynamic (can add fields any time!)
10 [Link] = "Tyler Durden"
38
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.
39
Operator Overloading
class Point:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
p1 = Point(1, 2)
p2 = Point(2, 3) Python didn't know how to
print(p1+p2) add two Point objects
Output together.
Traceback (most recent call last):
File "<string>", line 9, in <module> print(p1+p2)
TypeError: unsupported operand type(s) for +:
'Point' and 'Point' 40
Operator Overloading
To overload the + operator, we will need to implement
__add__() function in the class.
class Point:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __add__(self, other):
x = self.x + other.x
y = self.y + other.y p1 = Point(1, 2)
return Point(x, y) p2 = Point(2, 3)
result=p+p1
print(result.x,result.y) 41
Operator Overloading
>>> p1 = Point(2,3)
>>> print(p1)
<__main__.Point object at 0x00000000031F8CC0>
Suppose we want the print() function to print the
coordinates of the Point object instead of what we got. We
can define a __str__() method in our class that controls
how the object gets printed.
42
Operator Overloading
class Point:
def __init__(self, x = 0, y = 0):
self.x = x
self.y = y
“““Using special functions, we can make our class
compatible with built-in functions.”””
def __str__(self):
return "({0},{1})".format(self.x,self.y)
43
Overloading the less than operator
class Point:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __str__(self):
p1 = Point(1,1)
return "({0},{1})".format(self.x, self.y)
p2 = Point(-2,-
def __lt__(self, other): 3)
self_mag = (self.x ** 2) + (self.y ** 2) p3 = Point(1,-1)
other_mag = (other.x ** 2) + (other.y ** 2)
# use less than
return self_mag < other_mag print(p1<p2)
print(p2<p3)
print(p1<p3) 44
Operator Overloading
• operator overloading: You can define functions so that
Python's built-in operators can be used with your class.
Operator Class Method Operator Class Method
- __neg__(self, other) == __eq__(self, other)
+ __pos__(self, other) != __ne__(self, other)
* __mul__(self, other) < __lt__(self, other)
/ __truediv__(self, other) > __gt__(self, other)
Unary Operators <= __le__(self, other)
- __neg__(self) >= __ge__(self, other)
+ __pos__(self)
45
Inheritance
• Inheritance enables us to define a class that takes all
the functionality from a parent class and allows us to add
more.
• 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.
class BaseClass:
Body of base class
class DerivedClass(BaseClass):
Body of derived class
46
Inheritance
class name(superclass):
statements
– Example:
class Point3D(Point): # Point3D extends Point
z = 0
...
• Python also supports multiple inheritance
class name(superclass, ..., superclass):
statements
(if > 1 superclass has the same field/method, conflicts are resolved in left-to-right order)
47
Calling Superclass Methods
• methods: [Link](object, parameters)
• constructors: class.__init__(parameters)
class Point3D(Point):
z = 0
def __init__(self, x, y, z):
Point.__init__(self, x, y)
self.z = z
def translate(self, dx, dy, dz):
[Link](self, dx, dy)
self.z += dz
48
#Base Class Inheritance Example
class index:
def __init__(self):
self._count=0
def display(self):
print('count='+str(self._count))
def incr(self):
i=NewIndex()
self._count+=1
[Link]()
[Link]()
#Derived Class
[Link]()
class NewIndex(index):
[Link]()
def __init__(self):
[Link]()
super().__init__()
[Link]()
[Link]()
def decr(self):
[Link]()
self._count+=1
Inheritance Example
Execution during Inheritance:
• Construction of object always proceeds from base towards
derived.
• So, in above example base class __init__() function is
called first followed by derived class __init__() function.
• Derived class object contains all base class data. So _count
is available in derived class.
50
Types of Variables
Effect of private, public and protected is achieved by
following a convention while creating variable names. This
convention is shown below:
• count-treated as Public variable
• _count-treated as protected variable
• __count-treated as private variable
51
Types of Inheritance
There are five types of inheritance in python programming:
1). Single inheritance
2). Multiple inheritance
3). Multilevel inheritance
4). Hierarchical inheritance
5). Hybrid inheritance
52
Types of Inheritance
How to copy all properties of an object to another object
in Python?
class MyClass(object):
def __init__(self):
[Link] = 1
[Link] = 2 # super() is used to call the parent class’s
obj1 = MyClass()
obj2 = MyClass()
[Link] = 25 # __dict__ provides the
obj2.__dict__.update(obj1.__dict__) dictionary containing the
information about the class
namespace. update() adds
print([Link]) dictionary key-values pairs in to
print([Link]) dict of obj2.
53
Use of Super()
The super() builtin returns a proxy object (temporary object of
the superclass) that allows us to access methods of the base
class.
In Python, super() has two major use cases:
• Allows us to avoid using the base class name explicitly
• Working with Multiple Inheritance
54
Use of Super()
#super() with Single Inheritance
class Mammal(object):
def __init__(self, mammalName):
print(mammalName, 'is a warm-blooded animal.')
class Dog(Mammal):
def __init__(self):
print('Dog has four legs.')
super().__init__('Dog')
d1 = Dog()
55
Use of Super()
In above example called the __init__() method of the
Mammal class (from the Dog class) using code
super().__init__('Dog')
instead of
Mammal.__init__(self, 'Dog')
d1 = Dog()
56
Use of Super()
In above example called the __init__() method of the
Mammal class (from the Dog class) using code
super().__init__('Dog')
instead of
Mammal.__init__(self, 'Dog')
d1 = Dog()
57
Method Resolution Order (MRO)
Method Resolution Order (MRO) is the order in which
methods should be inherited in the presence of multiple
inheritance. You can view the MRO by using the
__mro__ attribute.
>>>Dog.__mro__
(<class 'Dog'>,
<class 'NonMarineMammal'>,
<class 'NonWingedMammal'>,
<class 'Mammal'>,
<class 'Animal'>,
<class 'object'>)
58
Polymorphism
Polymorphism is taken from the Greek words Poly
(many) and morphism (forms).
It refers to the use of a single type entity (method,
operator or object) to represent different types in different
scenarios.
Different purpose of Polymorphism are Duck Typing,
Operator overloading and Method overloading, and
Method overriding.
This polymorphism process can be achieved
in two main ways namely overloading and
overriding. 59
Polymorphism
Polymorphism is taken from the Greek words Poly
(many) and morphism (forms).
It refers to the use of a single type entity (method,
operator or object) to represent different types in different
scenarios.
Different purpose of Polymorphism are Duck Typing,
Operator overloading and Method overloading, and
Method overriding.
This polymorphism process can be achieved
in two main ways namely overloading and
overriding. 60