Understanding
OOP with Python
Unit 2(part 2)
By Prof.Hitesh Prajapati
Multiple Inheritance and the Lookup
Multiple inheritance in Python allows a class to inherit attributes and
methods from multiple parent classes. This feature provides flexibility
but can sometimes lead to complications, such as method naming
conflicts or ambiguity. To address these issues, Python uses a method
resolution order (MRO) mechanism, which determines the order in
which base classes are considered during method lookup.
When a class inherits from multiple classes, it inherits both attributes
and methods. The super() function is used to call methods from parent
classes. In Python, super() is used to access the parent class’s methods
and attributes, and it takes arguments to specify which parent class to
access.
Example
class parent:
In this example, the C def show(self):
class inherits from print("Parent class")
both A and B, and class child:
overrides the show() def show(self):
method. When C’s print("Child class")
show() method is
called, it uses super() class C(parent,child):
to access and call the def __init__(self):
super().show()
show() methods from super(parent,self).show()
A and B, respectively,
in the correct order, as obj = C()
determined by the Output:
MRO. Parent class
Child class
Decorators
Python decorators are a powerful feature that enables you to
modify or extend the behavior of a function without altering its
source code. They achieve this by wrapping the original function
with a new function, called the wrapper, which contains the
desired modifications.
Define a decorator function: A decorator function takes a function
as an argument and returns a new function, which is the wrapper.
The decorator function is denoted by the @ symbol
Decorators
def my_decorator(func):
def wrapper():
print("Something before the function.")
func()
print("Something after the function.")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
say_hello()
In the example above, say_hello is the original function, and my_decorator
is the decorator function. After applying the decorator, say_hello is replaced
with the wrapper function returned by my_decorator.
Decorators
Apply the decorator: When you apply a decorator to a function using the
@ symbol, Python replaces the original function with the wrapper
returned by the decorator.
The wrapper function: The wrapper function contains the desired
modifications to the original function. In this case, it prints messages
before and after calling the original function.
When you call the decorated function (say_hello()), you’ll see the
output:
Something before the function.
Hello!
Something after the function.
Static and Class Methods
In Python, a static method is a method that is bound to a class rather than an
instance of the class. It does not have access to instance-specific data and is
primarily used for utility functions that don’t depend on the state of the object.
class Name:
@staticmethod
def add(x, y):
return x + y
print(Name.add(5,4))
Here, add is a static method because it doesn’t depend on any instance-specific
data.
Static and Class Methods
A class method, on the other hand, is a method that is bound to a class and has
access to class-specific data. It is defined using the @classmethod decorator:
class Employee:
num_employees = 0
def __init__(self, name, salary): Employee("hitesh", 1000)
self.name = name
Employee.display_num_employ
self.salary = salary
ees()
Employee.num_employees += 1
@classmethod
def display_num_employees(cls):
print(f"Number of employees: {cls.num_employees}")
Static and Class Methods
The class method in Python is a method, which is bound to the class but not the object of that class.
The static methods are also same but there are some basic differences. For class methods, we need to
specify @classmethod decorator, and for static method @staticmethod decorator is used.
from datetime import date as dt
class Employee: @classmethod
def __init__(self, name, age): def emp_from_year(emp_class, name, year):
self.name = name return emp_class(name, dt.today().year - year)
self.age = age
def __str__(self):
@staticmethod return 'Employee Name: {} and Age: {}'.format(self.name, self.age)
def isAdult(age):
if age > 18: print(Employee('Dhiman', 25))
return True print( Employee.emp_from_year('Subhas', 1987))
else: print(Employee.isAdult(25))
return False print(Employee.isAdult(16))
Static and Class Methods
File I/O
Python provides various ways to interact with files, including reading and
writing text and binary data. Here’s a comprehensive overview:
Modes
1. Text Mode :
● 'r': Read-only, starts at the beginning of the file.
● 'w': Write-only, truncates the file to zero length if it exists,
creates a new file if it doesn’t.
● 'a': Append-only, starts at the end of the file.
● 'r+', 'w+', 'a+': Read-write, starts at the beginning of the file (or
end for 'a+').
2. Binary Mode ('rb', 'wb', 'ab', 'r+b', 'w+b', 'a+b'):
Same as text modes, but for binary data.
File I/O
open(file_name, mode)
● file_name: The name of the file to open.
● mode: The mode in which to open the file (e.g., 'r', 'w', 'rb', etc.).
Reading from a File
● read(size=-1): Reads up to size bytes from the file. Default is to
read the entire file.
● readline(): Reads a single line from the file.
● readlines(): Reads all lines from the file into a list.
File I/O
Writing to a File
● write(string): Writes string to the file.
● writelines(lines): Writes a list of strings to the file.
File Object Attributes
● closed: A boolean indicating whether the file is closed.
● name: The name of the file.
● mode: The mode in which the file was opened.
File I/O
fo = open("hello.txt","wb")
with open("hello.txt", "a") as
print ("Name of the file: ", fo.name)
file:
print ("Closed or not : ", fo.closed)
file.write("This is an
print ("Opening mode : ", fo.mode)
appended line.\n")
with open("image.png", "rb") as
with open("hello.txt", "w") as file:
file:
file.write("Hello, World!")
image_data = file.read()
print(image_data)
with open("hello.txt", "r") as file:
content = file.read()
print(content)