OOP’s Concept
1. what is the difference between print and return?
Ans: print is a function and return is a keyword.
print():
Purpose: print() is used to display output to the console or terminal.
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.
Example: def greet():
print("Hello, Devender")
greet() # Output: 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.
Example: def add(a, b):
return a + b # Return the sum of a and b
result = add(10, 20) # Assign the return value to a variable
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
print("Start") # Step 2: This line is executed first
greet() # Step 3: The function is called, execution jumps into the function
print("End") # Step 5: After the function call, execution resumes here
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.
Syntax of a Class: class ClassName:
def __init__(self, parameters):
# Initialization of object attributes
self.attribute = parameters
def method_name(self):
# Define some behavior
pass
Example: class Person:
def __init__(self, name, age):
self.name = name # Attribute
self.age = age # Attribute
def greet(self):
print(f"Hello, my name is {self.name} and I am {self.age} years old.")
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.
Creating an Object (Instantiation):
p1 = Person("John", 36) # p1 is an object of the Person class
p2 = Person("Alice", 28) # p2 is another object of the Person 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.
Syntax: class ClassName:
def __init__(self, parameters):
# Initialization code
Example: class Person:
def __init__(self, name, age):
# Assign the 'name' and 'age' attributes to the instance
self.name = name # self.name is an instance attribute
self.age = age # self.age is an instance attribute
# Creating an instance of the Person class
p1 = Person("John", 36)
print(p1.name) # Output: John
print(p1.age) # Output: 36
Why Use __init__()?
It allows you to set up the object's attributes at the time of creation.
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.
Example: class Person:
pass # No __init__ defined
p1 = Person() # Object created, but no attributes
p1.name = "John" # You'd have to set attributes manually
p1.age = 36
print(p1.name) # Output: John
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.
Key Points About __str__():
It is intended to return a human-readable string that describes the object.
It is often used to make debugging and logging easier by providing useful information
about an object when it is printed.
The __str__() method should return a string that is easy to read and understand.
Syntax:
You define the __str__() method inside a class, and it must return a string.
class ClassName:
def __str__(self):
return "some string representation"
Example Without __str__() modification :
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
p1 = Person("John", 36)
print(p1) # Output: <__main__.Person object at 0x15039e602100>
Example With __str__() modification :
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f"{self.name}({self.age})"
p1 = Person("John", 36)
print(p1) # Output: 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.
Key Concepts of Inheritance:
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.
Types of Inheritance in Python:
Single Inheritance: The child class inherits from a single parent class.
Example: class Parent:
def display(self):
print("This is the Parent class.")
class Child(Parent):
pass
c = Child()
c.display() # Inherited from Parent class
Multiple Inheritance: The child class inherits from more than one parent class.
Example: class Parent1:
def display1(self):
print("Parent1 display method")
class Parent2:
def display2(self):
print("Parent2 display method")
class Child(Parent1, Parent2):
pass
c = Child()
c.display1() # Inherited from Parent1
c.display2() # Inherited from Parent2
Multilevel Inheritance: A class can inherit from another class, which in turn inherits from
another class. This forms a chain of inheritance.
Example: class GrandParent:
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()
c.show_grandparent() # Inherited from GrandParent
c.show_parent() # Inherited from Parent
c.show_child() # Defined in Child
Hierarchical Inheritance: Multiple child classes inherit from the same parent class.
Example: class Parent:
def display(self):
print("Parent class")
class Child1(Parent):
pass
class Child2(Parent):
pass
c1 = Child1()
c2 = Child2()
c1.display() # Inherited from Parent
c2.display() # Inherited from Parent
Hybrid Inheritance: A combination of two or more types of inheritance.
Example: class Parent:
def display(self):
print("Parent class")
class Child1(Parent):
pass
class Child2(Parent):
pass
class GrandChild(Child1, Child2):
pass
gc = GrandChild()
gc.display() # Inherited from Parent
Method Resolution Order (MRO):
In Python, when a child class inherits from multiple parent classes,
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.
You can view the MRO of a class using ClassName.mro() or ClassName.__mro__.
For example: class A:
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")
class D(B, C):
pass
d = D()
d.method() # Calls B's method due to MRO
print(D.mro())
Output: B's method
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class
'object'>]
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.
Example: self.var, def method(self)
Protected: Accessible within the class and subclasses. Marked with a single underscore
(_).
Example: self._var, def _method(self)
Private: Accessible only within the class. Marked with double underscores (__), causing
name mangling.
Example: self.__var, def __method(self)
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:
A module is typically a .py file.
You can import and use the code from a module in other Python files.
Python provides many built-in modules (like math, os, sys) and you can create your own
custom modules.
To create a module just save the code you want in a file with the file extension .py
Example:
Save this code in a file named mymodule.py
def greeting(name):
print("Hello, " + 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
mymodule.greeting("Jonathan") # Output: Hello, Jonathan
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
person1 = { "name": "John", "age": 36, "country": "Norway"}
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
Create an alias for mymodule called mx:
import mymodule as mx
a = mx.person1["age"]
print(a) # Output: 36
Using the dir() Function
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.
Import From Module
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):
print("Hello, " + name)
person1 = {"name": "John","age": 36,"country": "Norway"}
Example
Import only the person1 dictionary from the module
from mymodule import person1
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"]
Python JSON [JavaScript object notation]
JSON is a syntax for storing and exchanging data.
JSON is text, written with JavaScript object notation.
Python has a built-in package called json, which can be used to work with JSON data
to use json, we need to import json package.
example: import json
Parse JSON - Convert from JSON to Python
If you have a JSON string, you can parse it by using the json.loads() method.
The result will be a Python dictionary.
Example
Convert from JSON to Python:
import json
# some JSON:
x = '{ "name":"John", "age":30, "city":"New York"}'
# parse x:
y = json.loads(x)
# the result is a Python dictionary:
print(y["age"]) # Output: 30
print(type(y)) # Output: <class 'dict'>
Convert from Python to JSON
If you have a Python object, you can convert it into a JSON string by using the json.dumps()
method.
Example
Convert from Python to JSON:
import json
# a Python object (dict):
x = { "name": "John", "age": 30,"city": "New York"}
# convert into JSON:
y = json.dumps(x)
# the result is a JSON string:
print(y) #Output: {"name": "John", "age": 30, "city": "New York"}
print(type(y)) #Output: <class 'str'>
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(["apple", "bananas"])) #Output: ["apple", "bananas"]
print(json.dumps(("apple", "bananas"))) #Output: ["apple", "bananas"]
print(json.dumps("hello")) #Output: "hello"
print(json.dumps(42)) #Output: 42
print(json.dumps(31.76)) #Output: 31.76
print(json.dumps(True)) #Output: true
print(json.dumps(False)) #Output:false
print(json.dumps(None)) #Output: null
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
Example: import json
x = { "name": "John",
"age": 30,
"married": True,
"divorced": False,
"children": ("Ann","Billy"),
"pets": None,
"cars": [{"model": "BMW 230", "mpg": 27.5},
{"model": "Ford Edge", "mpg": 24.1}]
# convert into JSON:
y = json.dumps(x)
# the result is a JSON string:
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}]
Format the Result
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
Use the indent parameter to define the numbers of indents:
json.dumps(x, indent=4)
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
Example
Use the separators parameter to change the default separator:
json.dumps(x, indent=4, separators=(". ", " = "))
Order the Result
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:
json.dumps(x, indent=4, sort_keys=True)
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.
The main advantages of package statement are
1. We can resolve naming conflicts.
2. We can identify our components uniquely.
3. It improves modularity of the application.
What is pip?
PIP (Pip Installs Packages) is the package installer for Python.
It allows you to install and manage additional libraries and dependencies that are not
included in the Python standard library.
With PIP, you can download packages from the Python Package Index (PyPI), which is
the official repository for Python packages.
Key features of 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")
SyntaxError: invalid syntax
Eg 2: print "Hello"
SyntaxError: Missing parentheses in call to 'print'
Note: Programmer is responsible to correct these syntax errors. Once all syntax errors are
corrected then only program execution will be started.
Runtime Errors: Also known as exceptions.
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.
Eg: print(10/0) ==>ZeroDivisionError: division by zero
print(10/"ten") ==>TypeError: unsupported operand type(s) for /: 'int' and 'str'
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.
What is Exception handling?
Exception handling is a mechanism to handle runtime errors or unexcepted events that
occurs during the execution of a program.
Such as FileNotFoundError, ArithmeticError, OSError, NameError etc.,
The Exception class is the base class for all built-in exceptions.
All runtime exceptions (like FileNotFoundError, ArithmeticError, etc.) are subclasses of
Exception.
Types of Exceptions:
In Python there are 2 types of exceptions are possible.
1. Predefined Exceptions
2. User Definded Exceptions
Predefined Exceptions: Also known as in-built 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
User Defined Exceptions: Also known as Customized Exceptions or Programmatic Exceptions.
User-defined exceptions are custom exception classes created by developers to handle
specific error.
Some time we have to define and raise exceptions explicitly to indicate that something
goes wrong, such type of exceptions is called User Defined Exceptions or Customized
Exceptions.
Programmer is responsible to define these exceptions and Python not having any idea
about these. Hence, we have to raise explicitly based on our requirement by using
“raise" keyword.
Eg: InSufficientFundsException
InvalidInputException
TooYoungException
TooOldException
How to Define and Raise Customized Exceptions:
Every exception in Python is a class that extends Exception class either directly or indirectly.
Syntax: class classname(predefined_exception_class_name):
def __init__(self,arg):
self.msg=arg
TooYoungException is our class name which is the child class of Exception
We can raise exception by using raise keyword as follows
raise TooYoungException("message")
Eg: class TooYoungException(Exception):
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:
raise TooOldException("Your age already crossed marriage age...no chance of getting
marriage")
else:
print("You will get match details soon by email!!!")
# Output 1: Enter Age:17
Plz wait some more time you will get best match soon!!!
# Output 2: Enter Age:62
Your age already crossed marriage age...no chance of getting marriage
# Output 3: Enter Age:27
You will get match details soon by email!!!
Note:
raise keyword is best suitable for customized exceptions but not for pre-defined exceptions