OOP
OOP
print():
Effect: It outputs the result to the console but does not affect the flow of the program or the
values within it.
Scope: print() can be used anywhere in the code, but it doesn't pass values to other parts of the
program.
print("Hello, Devender")
return:
Purpose: return is used to send a value back from a function to the caller. This allows the
function to pass data that can be used in other parts of the program.
Effect: return terminates the function execution and sends a value back to the caller, which can
be assigned to a variable or used in an expression.
Scope: The value returned by return can be stored, passed to other functions, or manipulated
further.
print(result) # Output: 30
Function Execution Flow:
When Python encounters a function definition, it does not execute the function's code
line by line immediately. Instead, it simply registers the function, making it available to
be called later.
The execution of the code inside the function only happens when the function is called.
At that point, Python jumps into the function, executes its lines one by one, and then
returns to the place where the function was called.
Example:
def greet(): # Step 1: The function definition is read but not executed
print("Hello") # Step 4: This line will only execute when the function is called
greet() # Step 3: The function is called, execution jumps into the function
Class
A class is like a blueprint or template for creating objects.
It defines attributes (data) and methods (functions) that the objects created from the
class will have.
A class defines the structure and behavior of the objects.
It does not store actual data, but it specifies what kind of data (attributes) and behavior
(methods) the objects will have.
self.attribute = parameters
def method_name(self):
pass
Example: class Person:
def greet(self):
Object
Objects are instances of a class.
Each object is created from a class will have its own data, but it will share the structure
(attributes and methods) defined by the class.
__init__() Function
The __init__() method in Python is a special method, also called the constructor.
It is automatically called when a new object (or instance) of a class is created.
Its main role is to initialize the object's attributes and set them up with any initial values.
First Parameter - self: The first parameter of __init__() is always self. This refers to the
instance that is being created. Through self, you can assign values to instance variables.
# Initialization code
Example: class Person:
p1 = Person("John", 36)
print(p1.age) # Output: 36
You can ensure that every object of the class is properly initialized with the necessary data
before it can be used.
Without __init__():
If you don't define __init__(), the object can still be created, but no attributes would be
initialized unless you manually set them later.
p1.age = 36
print(p1.age) # Output: 36
__str__() function
The __str__() function in Python is a special or magic method that is used to define the
"informal" or "user-friendly" string representation of an object.
When you print an object or use str() on an object, Python internally calls the __str__()
method to get the string representation.
Syntax:
You define the __str__() method inside a class, and it must return a string.
class ClassName:
def __str__(self):
class Person:
self.name = name
self.age = age
p1 = Person("John", 36)
class Person:
self.name = name
self.age = age
def __str__(self):
return f"{self.name}({self.age})"
p1 = Person("John", 36)
INHERITANCE
Inheritance is a fundamental concept in object-oriented programming (OOP) that allows
one class (the child or subclass) to inherit attributes and behaviors (methods) from
another class (the parent or superclass).
This enables code reusability, a hierarchical class structure, and the extension or
modification of existing functionality without altering the original class.
Parent (Base) Class: The class whose properties (attributes and methods) are inherited
by another class.
Child (Derived) Class: The class that inherits properties from the parent class. It can
extend or override the functionality of the parent class.
Single Inheritance: The child class inherits from a single parent class.
def display(self):
pass
c = Child()
Multiple Inheritance: The child class inherits from more than one parent class.
def display1(self):
class Parent2:
def display2(self):
pass
c = Child()
Multilevel Inheritance: A class can inherit from another class, which in turn inherits from
another class. This forms a chain of inheritance.
def show_grandparent(self):
print("Grandparent class")
class Parent(GrandParent):
def show_parent(self):
print("Parent class")
class Child(Parent):
def show_child(self):
print("Child class")
c = Child()
Hierarchical Inheritance: Multiple child classes inherit from the same parent class.
def display(self):
print("Parent class")
class Child1(Parent):
pass
class Child2(Parent):
pass
c1 = Child1()
c2 = Child2()
def display(self):
print("Parent class")
class Child1(Parent):
pass
class Child2(Parent):
pass
pass
gc = GrandChild()
the Method Resolution Order (MRO) determines the order in which the parent classes are
searched for a method. This is particularly relevant for multiple inheritance.
def method(self):
print("A's method")
class B(A):
def method(self):
print("B's method")
class C(A):
def method(self):
print("C's method")
pass
d = D()
print(D.mro())
Advantages of Inheritance:
Code Reusability: Inheritance allows child classes to reuse code from parent classes,
reducing redundancy.
Modularity: Class hierarchies can be designed to be modular, separating logic across
different classes.
Maintainability: Changes in the parent class can propagate across all child classes,
reducing the need for redundant updates.
Extensibility: Child classes can easily extend or modify behavior, making the system
flexible and scalable.
Disadvantages of Inheritance:
Increased Coupling: Tight coupling between child and parent classes can make changes
difficult, especially if the inheritance structure is complex.
Fragile Base Class Problem: Modifying a parent class might inadvertently break the
behavior of child classes, leading to bugs that are hard to trace.
Overuse: Over-relying on inheritance can lead to rigid code structures and decrease
flexibility when modifying the class design.
ENCAPSULATION
The process of wrapping or bundling the data (attributes) and methods (functions) that
work on the data into a single unit is called "Encapsulation".
It also restricts direct access to some of the object's components, thereby hiding the
internal implementation details and protecting the data from unintended or harmful
changes.
Data Hiding:
The process of restricting the direct access and providing the indirect access is known as "Data
Hiding".
Public: Accessible from anywhere (inside and outside the class). No special notation
required.
Protected: Accessible within the class and subclasses. Marked with a single underscore
(_).
Private: Accessible only within the class. Marked with double underscores (__), causing
name mangling.
What is module?
A module is a file that contains Python code, which can include variables, functions, classes, and
executable statements.
Modules help organize code into logical blocks and allow for code reuse across multiple
programs.
Key Points:
To create a module just save the code you want in a file with the file extension .py
Example:
def greeting(name):
Use a Module
Now we can use the module we just created, by using the import statement
Example
Import the module named mymodule, and call the greeting function
import mymodule
Note: When using a function from a module, use the syntax: module_name.function_name.
Variables in Module
The module can contain functions, as already described, but also variables of all types (arrays,
dictionaries, objects etc)
Example
Save this code in the file mymodule.py
Example
Import the module named mymodule, and access the person1 dictionary
import mymodule
a = mymodule.person1["age"]
print(a) # Output: 36
Naming a Module
You can name the module file whatever you like, but it must have the file extension .py
Re-naming a Module
You can create an alias when you import a module, by using the as keyword
Example
import mymodule as mx
a = mx.person1["age"]
print(a) # Output: 36
There is a built-in function to list all the function names (or variable names) in a module. The
dir() function.
import platform
x = dir(platform)
print(x)
Note: The dir() function can be used on all modules, also the ones you create yourself.
You can choose to import only parts from a module, by using the from keyword.
Example
The module named mymodule has one function and one dictionary:
def greeting(name):
Example
print (person1["age"])
Note: When importing using the from keyword, do not use the module name when referring to
elements in the module. Example: person1["age"], not mymodule.person1["age"]
If you have a JSON string, you can parse it by using the json.loads() method.
Example
# some JSON:
# parse x:
y = json.loads(x)
print(y["age"]) # Output: 30
If you have a Python object, you can convert it into a JSON string by using the json.dumps()
method.
Example
import json
y = json.dumps(x)
Example
Convert Python objects into JSON strings, and print the values:
import json
print(json.dumps({"name": "John", "age": 30})) #Output: {"name": "John", "age": 30}
print(json.dumps(42)) #Output: 42
print(json.dumps(False)) #Output:false
When you convert from Python to JSON, Python objects are converted into the JSON
(JavaScript) equivalent:
Python JSON
dict Object
list Array
tuple Array
str String
int Number
float Number
True true
False False
None null
x = { "name": "John",
"age": 30,
"married": True,
"divorced": False,
"children": ("Ann","Billy"),
"pets": None,
"cars": [{"model": "BMW 230", "mpg": 27.5},
y = json.dumps(x)
print(y)
Output: {"name": "John", "age": 30, "married": true, "divorced": false, "children":
["Ann","Billy"], "pets": null, "cars": [{"model": "BMW 230", "mpg": 27.5}, {"model": "Ford Edge",
"mpg": 24.1}]
The example above prints a JSON string, but it is not very easy to read, with no indentations
and line breaks.
The json.dumps() method has parameters to make it easier to read the result:
Example
json.dumps(x, indent=4)
Output: {
"name": "John",
"age": 30,
"married": true,
"divorced": false,
"children": [
"Ann",
"Billy"
],
"pets": null,
"cars": [
"mpg": 27.5
},
"mpg": 24.1
Example
The json.dumps() method has parameters to order the keys in the result:
Example
Use the sort_keys parameter to specify if the result should be sorted or not:
Package
It is an encapsulation mechanism to group related modules into a single unit.
package is nothing but folder or directory which represents collection of Python
modules.
Any folder or directory contains __init__.py file, is considered as a Python package. This
file can be empty.
A package can contains sub packages also.
What is pip?
Installation of packages: You can easily install any package by running a simple
command like pip install <package_name>.
Dependency management: PIP automatically handles dependencies for the packages
you install.
Upgrading packages: PIP also allows you to upgrade packages using pip install --
upgrade <package_name>.
Listing installed packages: You can list all installed packages with pip list.
Exception Handling
In any programming language there are 2 types of errors are possible.
1. Syntax Errors
2. Runtime Errors
Syntax Errors: The errors which occurs because of invalid syntax are called syntax
errors.
Eg 1: x=10
if x==10
print("Hello")
Eg 2: print "Hello"
Note: Programmer is responsible to correct these syntax errors. Once all syntax errors are
While executing the program if something goes wrong because of end user input or
programming logic or memory problems etc then we will get Runtime Errors.
x=int(input("Enter Number:"))
print(x)
1. Eg: ZeroDivisionError
2. TypeError
3. ValueError
4. FileNotFoundError
5.EOFError
6.SleepingError
7.TyrePuncturedError
It is highly recommended to handle exceptions. The main objective of exception
handling
is Graceful Termination of the program (i.e we should not block our resources and we
should not miss anything)
Exception handling does not mean repairing exception. We have to define alternative
way to continue rest of the program normally.
Note: Exception Handling concept applicable for Runtime Errors but not for syntax errors
What is Exception?
An unwanted and unexpected event that disturbs normal flow of program is called Exception.
Types of Exceptions:
1. Predefined Exceptions
2. User Definded Exceptions
The exceptions which are raised automatically by Python virtual machine whenever a particular
event occurs, are called pre-defined exceptions.
Eg 1: Whenever we are trying to perform Division by zero, automatically Python will raise
ZeroDivisionError.
print(10/0)
Eg 2: Whenever we are trying to convert input value to int type and if input value is not int
value then Python will raise ValueError automatically.
x=int("ten") ===>ValueError
Eg: InSufficientFundsException
InvalidInputException
TooYoungException
TooOldException
Every exception in Python is a class that extends Exception class either directly or indirectly.
def __init__(self,arg):
self.msg=arg
raise TooYoungException("message")
def __init__(self,arg):
self.msg=arg
class TooOldException(Exception):
def __init__(self,arg):
self.msg=arg
age=int(input("Enter Age:"))
if age>18:
raise TooYoungException("Plz wait some more time you will get best match soon!!!")
elif age<89:
else:
Plz wait some more time you will get best match soon!!!
Note:
raise keyword is best suitable for customized exceptions but not for pre-defined exceptions