Sunday, May 17, 2026

Python Material - Part - 21 - Oops - 4

 __author__ = "Narendra Boyina"

# -----------------------------------------------------------------------------
# Copyright (c) 2025 BR Technologies PVT LTD
# -----------------------------------------------------------------------------
"""
Topics to be covered in today's class:
--> Inheritance / Single inheritance
--> Multiple inheritance
--> multi-level inheritance
--> Hierarchial inheritance
--> Hybrid inheritance
--> issubclass
--> isinstance
"""


""" Inheritance / Single inheritance
Inheritance − The transfer of the characteristics of a class to other classes that are derived from it.

Instead of starting from a scratch, you can create a class by deriving it from a pre-existing class
by writing the parent class name in parentheses after the new_class_name.

Single Inheritance Syntax:
Derived class is declared much like it's parent class.

class ChildClassName(ParentClass):
'Optional class documentation string'
class_suite (class variables , methods)


The child class inherits the attributes of its parent class, and you can use those attributes as if they were defined in the child class.
A child class can also override data members and methods from the parent.

"""
class Base():
pass # Empty Class

class Derived(Base):
pass # Empty Class

"""
Single Inheritance
When a child class inherits only a single parent class."""

class Bhaskarao: # define parent class
parentAttr = 100 # class variable/local variable/ attribute

def __init__(self):
print ("Calling parent constructor")

def parentMethod(self):
print ('Calling parent method')

def setAttr_Name(self, attr):
Bhaskarao.parentAttr = attr # class_name.class_variable

def getAttr_Name(self):
print ("Parent attribute value:", Bhaskarao.parentAttr)

def python(self):
print("venkat")
print("priyanka")
print("subhashini")
print("sujana")
print("rindha")


# priyanka = Bhaskarao() # obj/instance creation
# print("class attribute value:",priyanka.parentAttr)
# priyanka.parentMethod()
# priyanka.setAttr_Name(444)
# priyanka.getAttr_Name()
# priyanka.python()


# single Inheritance
class Narendra(Bhaskarao): # define derived class / child class

def __init__(self):
print ("Calling child constructor")
def Narendra_Method(self):
print ('Calling child method')


# child_obj = Narendra() # instance of child , immediately child's init method will be executed
# child_obj.Narendra_Method()
# child_obj.python() # calls parent's method
# child_obj.parentMethod() # calls parent's method
# child_obj.setAttr_Name(200) # again call parent's method
# child_obj.getAttr_Name() # again call parent's method
"""
When the above code is executed, it produces the following result −

Calling child constructor
Calling child method
Calling parent method
Parent attribute : 200
"""
"""
############# Multiple inheritance #############
When a child class inherits from more than one parent class
or
# In a similar way, you can drive a class from multiple parent classes as follows −

class A: # define your class A
.....

class B: # define your calss B
.....

class C(A, B): # subclass of A and B
.....
"""

class Chocolate:
def __init__(self):
print("calling chocolate method")

def ingedreint(self):
print("badam, pista and cashew are presented in this ")

def flavour(self):
print("choclate flavour")


class FiveStar:

def __init__(self):
print("calling five star method")

def taste(self):
print("completely filled with chocolate and caramel")

class Abcd:

def xyz(self):
print("called xyz method")


class DairyMilk(Chocolate, FiveStar, Abcd): # Multiple inheritance
Mahalakshmi = 444 # class attribute / class variable

def __init__(self):
print("calling Dairy Milk method")

def nutrition_facts(self):
print("energy contains: 4% \nproteins contain: 0% \nfat contains: 10% \ncarbohydrates contains: 5%")


# child_obj = DairyMilk()
# print(child_obj.Mahalakshmi)
# child_obj.nutrition_facts()
# child_obj.flavour()
# child_obj.taste()
# child_obj.ingedreint()
# child_obj.xyz()


""" ############# multi-level inheritance #############
When a child class becomes a parent class for another child class """

class subhashini(): # In general we called this(subhashini) as Base class
def abc(self):
print("called abc method available in subhashini class")

class venkat(subhashini): # In general we called this(venkat) as Derived class
def xyz(self):
print("called xyz method available in venkat class")

class ganesh(venkat): # In general we called this(ganesh) as Derived class
def ijk(self):
print("called ijk method available in ganesh class")

class rindha(ganesh):
def qwerty(self):
print("called qwerty method available in rindha class")

child_obj = rindha()
child_obj.xyz()
child_obj.abc()
child_obj.qwerty()
# print(issubclass(rindha, ganesh)) # True
# print(issubclass(rindha, venkat))
# print(issubclass(ganesh, rindha)) # False
# print(issubclass(venkat, rindha))

"""
How to check if a class is subclass of another?
Python provides a function issubclass() that directly tells us if a class is subclass of another class
You can use issubclass() or isinstance() functions to check a relationships of two classes and instances.
The issubclass(sub, sup) boolean function returns True, if the given subclass sub is indeed a subclass of the superclass sup.
The isinstance(obj, Class) boolean function returns True, if obj is an instance of class Class or is an instance of a subclass of Class
"""
# print(isinstance(child_obj, rindha))
# print(isinstance(child_obj, ganesh))
# print(isinstance(child_obj, venkat))
# print(isinstance(child_obj, subhashini))


""" ############# Hierarchial inheritance #############
single class inherited by multiple classes

or
When more than one derived classes are created from a single base,
this type of inheritance is called hierarchical inheritance. """

class FiveStar:
cost = 30 # class_variable / attribute
def __init__(self):
print("calling five star method")
def qwerty(self):
print("called qwerty method available in rindha class")
def taste(self):
print("completely filled with chocolate and caramel")

class Narendra (FiveStar):
pass


class Varun(FiveStar):
pass

class Manikanta(FiveStar):
pass



"""Hybrid Inheritance

Hybrid inheritance is done when we have to mix different types of inheritance within a single program,
for example, mixing single inheritance with multiple inheritance or multiple inheritance within a single program
"""


Python Material - Part - 20 - Oops - 3

 __author__ = "Narendra Boyina"


from pandas.conftest import index

# -----------------------------------------------------------------------------
# Copyright (c) 2025 BR Technologies PVT LTD
# -----------------------------------------------------------------------------
"""
Topics to be covered in today's class:
--> hasattr , getattr, delattr
--> small bank application
--> Practice programs
"""


class Employee:
"""Common base class for all employees"""
empCount = 0 # class variable/ attribute

def __init__(self, name, salary):
"""as soon as created the instance, this method will be executed"""
self.name = name
self.salary = salary
Employee.empCount += 1 # class_name.class_variable
print("Employee count till now is :{} ".format(Employee.empCount))
# print("This is constructor method")
# print("Once created instance automatically this method will execute")
# print("How many times you will create new instace those many times this contructor method will execute aumatically")

def displayCount(self):
# using class variable inside method : Classname.ClassVariable
print("total employee count is {}".format(Employee.empCount))

def displayEmployee(self):
print("Name : ", self.name, ", Salary: ", self.salary)


# emp_1 = Employee("Narendra", 120000) # emp_1 (instance variable (object)) or attribute
# emp_1.displayCount() # by using object calling method
# print(emp_1.empCount) # by using object/instance calling the class variable
#
# emp_2 = Employee("Manasa", 30000)
# emp_2.displayCount()
# emp_2.displayEmployee()
#
# emp_3 = Employee("Surendra", 22000)
# emp_3.displayCount()
# emp_3.displayEmployee()
# emp_3.salary = 52000
# emp_3.displayEmployee()
#
# emp_2.displayEmployee()


"""Note:
If you have created multiple objects for the same class then, different objects located in different memory location
You can check memory locations in decimal format or hexa_decimal format
Narenrdra != manasa != Surendra"""

# print(id(emp_1)) #
# print(id(emp_2)) #
# print(id(emp_3)) #

"""You can add, remove, or modify attributes of classes and objects at any time """
# emp_1.age = 27 # Add an 'age' attribute,by using object
# print(emp_1.age)
# emp_2.name = 'ganesh' # Modify 'name' attribute's value.
# print(emp_2.name)
# # del emp_1.salary # Delete 'salary' attribute.
# # print(emp_1.salary) # it will give AttributeError
# print("Employee 2 salary is : {}".format(emp_2.salary))
# print(emp_2.name)

"""Instead of using the normal statements to access/modify/delete attributes,
you can use the following in-built methods """

""" The hasattr(obj,name) − to check if an attribute exists or not,
if attribute is present then return True else return False"""


# print(hasattr(emp_1, 'salary')) # already we have deleted so it will give False as output
# print(hasattr(emp_1, 'age')) # checking for age attribute --> True
# print(hasattr(emp_1, 'designation')) # False (designation attribute is not present so it will give False)
# print(hasattr(emp_2,'salary')) # True (I haven't deleted salary attribute to emp_2, I have deleted salary attribute for emp_1 object)

# # The setattr(obj,name,value) − to set an attribute. If attribute does not exist, then it would be created.
# setattr(emp_1, "salary", 146780)
# setattr(emp_1, "Designation", "Technical Lead")
#
# # """The getattr(obj, name[, default]) − to access the attribute of object """
# print(emp_1.salary) # instance_variable.class_variable
# print(getattr(emp_1, "salary"))
# print(emp_1.Designation)
# print(getattr(emp_1,"Designation"))
#
# """ The delattr(obj, name) − to delete an attribute."""
# delattr(emp_1,"salary")
# print(hasattr(emp_1, 'salary')) # Returns true if 'salary' attribute exists
#
# setattr(emp_1, 'salary', 70000) # Set attribute 'salary' at 7000
# s = getattr(emp_1, 'salary') # Returns value of 'salary' attribute
# print(s)
# print(emp_1.salary)
# delattr(emp_1, 'salary') # Delete attribute 'salary'
"""We in previous steps we have deleted salary attribute, so displaying result as False """
# print(hasattr(emp_1, 'salary')) # it will give False Reason: you have deleted in the before line
# print(emp_1.salary) # gives AttributeError Reason: Already deleted in the above line
#
#
# class Employee:
# """This class is designed to help HR to calculate year-end salary increases based on employee performance and other parameters"""
# pass
#
# print(Employee.__doc__, end=".")
#
# class Kruthika:
# """This class having the methods related to kruthika details """
# pass


# print(Kruthika.__doc__, end=".")
#
# class Meera:
# """This class having the methods related to kruthika details """
# pass
#
# print(Meera.__doc__)

"""
Python code
--> to open Multiple bank accounts
--> to deposit amounts
--> with draw amounts
--> to get balance from any particular account
"""

class BankAccount:
venkat =10

""" this code belongs to bank application which can perform creation of account, deposit, withdraw,get_balance """
def __init__(self, account_holder, balance=0):
"""
Initializes a new bank account.
:param account_holder: Name of the account holder
:param balance: Initial balance (default is 0)
"""
self.account_holder = account_holder
self.balance = balance

def deposit(self, amount):
"""
Deposits a specified amount into the account.
:param amount: The amount to deposit
"""
self.balance += amount
print(f"Deposited amount is {amount}. latest balance: {self.balance}")


def withdraw(self, with_draw_amount):
"""
Withdraws a specified amount from the account if sufficient balance exists.
:param amount: The amount to withdraw
"""
if with_draw_amount <= self.balance:
self.balance -= with_draw_amount # self.balance = self.balance - with_draw_amount
print(f"Withdrew {with_draw_amount}. Remaining balance: {self.balance}")
elif with_draw_amount > self.balance:
print(f"current balance in your account:{self.balance}, you are trying to withdraw {with_draw_amount} So Insufficient funds. ")


def get_balance(self):
"""
Returns the current balance of the account.
"""
print(f"{self.account_holder}'s Available balance: {self.balance}")
return self.balance


# Small bank application
# if __name__ == "__main__":
# # Create a new bank account for meera with an initial balance of $500
# Meera_account = BankAccount("Meera", 500) # init method will be executes as soon as you have created an object for a particular class
# #
# # # Deposit 500 into Meera's account
# Meera_account.deposit(500)
# #
# # # Withdraw200 from Meera's account
# Meera_account.withdraw(200)
# #
# # # Attempt to withdraw an amount greater than the balance
# Meera_account.withdraw(2000)
# #
# # # Check the final balance
# Meera_account.get_balance()
# #
# ganesh_account = BankAccount("ganesh", 500) # init method will be executes as soon as you have created an object for a particular class
# # Deposit 500 into Meera's account
# ganesh_account.deposit(50000)
# # Withdraw 200 from Meera's account
# ganesh_account.withdraw(10000)
# #
# Manikanta_account = BankAccount("Manikanta", 500) # init method will be executes as soon as you have created an object for a particular class
# # Deposit $500 into Meera's account
# Manikanta_account.deposit(100000)
# # Withdraw $200 from Meera's account
# Manikanta_account.withdraw(10000)
# #
# ganesh_account.get_balance() # this will give ganesh's Available balance





""" Practice programs """
""" Write a Python function that takes a list and returns a new list with unique elements of the first list."""


def unique_list(data):
req_list = []
for element in data:
if element not in req_list:
req_list.append(element)

print(req_list)


# data = [5, 3, 1, 3, 4, 5, 6, 6, 68, 8, 8, 8, 68]
# unique_list(data)

# x = set(data)
# print(list(x))


#
def unique_list(data):
req_list = [element for index, element in enumerate(data) if element not in data[ :index]] # omit starting address
print(req_list)

# data = [5, 3, 1, 3, 4, 5, 6, 6, 68, 8, 8, 8, 68]
# unique_list(data)

Python Material - Part - 19 - Oops - 2

 __author__ = "Narendra Boyina"


# -----------------------------------------------------------------------------
# Copyright (c) 2025 BR Technologies PVT LTD
#-----------------------------------------------------------------------------
"""
Topics to be covered in today's class:
--> Docstring with example
--> pass keyword with example
--> How to use class variable inside method
"""


class Salary_hike:
"""
This class is designed to help HR to calculate year-end salary increases based on employee performance and other parameters
"""
x = 100 # class variable / attribute

def __init__(self, EmpId, Expe, sal, Level, Rating):
self.EmpID = EmpId
self.Expe = Expe
self.Level = Level
self.Rating = Rating
if(Expe == 1 and Level == "c1" and Rating == "superstar" ):
print(" Hike is 25%,Salary after increment",((.25*sal)+sal))
elif(Expe == 1 and Level == "c1" and Rating == "star" ):
print(" Hike is 20%,Salary after increment",((.20*sal)+sal))
elif(Expe == 1 and Level == "c1" and Rating == "pillor" ):
print(" Hike is 15%,Salary after increment",((.15*sal)+sal))
elif(Expe == 1 and Level == "c1" and Rating == "below expectations" ):
print(" Hike is 9%,Salary after increment",((.10*sal)+sal))

elif((Expe == (2 or 3)) and Level == "c2" and Rating == "superstar" ):
print(" Hike is 18%,Salary after increment",((.18*sal)+sal))
elif((Expe == (2 or 3)) and Level == "c2" and Rating == "star" ):
print(" Hike is 15%,Salary after increment",((.15*sal)+sal))
elif((Expe == (2 or 3)) and Level == "c2" and Rating == "pillor" ):
print(" Hike is 10%,Salary after increment",((.10*sal)+sal))
elif((Expe == (2 or 3)) and Level == "c2" and Rating == "below expectations" ):
print(" Hike is 8%,Salary after increment",((.08*sal)+sal))

elif(Expe == (4 or 5 or 6) and Level == "c3" and Rating == "superstar" ):
print(" Hike is 15%,Salary after increment",((.15*sal)+sal))
elif(Expe == (4 or 5 or 6) and Level == "c3" and Rating == "star" ):
print(" Hike is 12%,Salary after increment",((.12*sal)+sal))
elif(Expe == (4 or 5 or 6) and Level == "c3" and Rating == "pillor" ):
print(" Hike is 8%,Salary after increment",((.08*sal)+sal))
elif(Expe == (4 or 5 or 6) and Level == "c3" and Rating == "below expectations" ):
print(" Hike is 6%,Salary after increment",((.06*sal)+sal))

elif(Expe == (7 or 8 or 9) and Level == ("c4" or "c5") and Rating == "superstar" ):
print(" Hike is 13%,Salary after increment",((.13*sal)+sal))
elif(Expe == (7 or 8 or 9) and Level == ("c4" or "c5") and Rating == "star" ):
print(" Hike is 9%,Salary after increment",((.09*sal)+sal))
elif(Expe == (7 or 8 or 9) and Level == ("c4" or "c5") and Rating == "pillor" ):
print(" Hike is 7%,Salary after increment",((.07*sal)+sal))
elif(Expe == (7 or 8 or 9) and Level == ("c4" or "c5") and Rating == "below expectations" ):
print(" Hike is 5%,Salary after increment",((.05*sal)+sal))

elif(Expe >=10 and Level == ("c6" or "c7") and Rating == "superstar" ):
print(" Hike is 10%,Salary after increment",((.10*sal)+sal))
elif(Expe >=10 and Level == ("c6" or "c7") and Rating == "star" ):
print(" Hike is 7%,Salary after increment",((.07*sal)+sal))
elif(Expe >=10 and Level == ("c6" or "c7") and Rating == "pillor" ):
print(" Hike is 5%,Salary after increment",((.05*sal)+sal))
elif(Expe >=10 and Level == ("c6" or "c7") and Rating == "below expectations" ):
print(" Hike is 3%,Salary after increment",((.03*sal)+sal))

else:
print("given values are not match, please provide proper input values")


# emp_1 = Salary_hike("HM0002162", 2, 32000, "c2", "star")
# print(emp_1.EmpID)
# print(emp_1.Level)

"""
We can create multiple instances of the same class, but each instance is independent of the others.
(i.e when we have created a new instance, it will be created in a new memory location)
"""

# emp_2 = Salary_hike("HM0001669", 4, 45000, "c3", "superstar")
#
# print(emp_2.EmpID)
# print(emp_2.Level)
#
# print(id(emp_1), id(emp_2) )

"""providing wrong values"""
# emp_3 = Salary_hike("HM0001669", 4, 45000, "c1", "superstar")

"""
Docstring: It is the first string inside the class and has a brief description of the class (documentation).
Although not mandatory, this is highly recommended.
documentation string, which can be accessed via ClassName.__doc__
"""

# print(Salary_hike.__doc__)

# import keyword
# print(keyword.kwlist)

"""
--> "pass" is a keyword ( or a statement) to indicate a "null" block. &
"pass" indicate that, nothing happens inside the function/class/conditional statements/ looping statement is empty.
--> "Pass keyword, can be used to efficiently add unimplemented items quickly."
--> pass can be placed on the same line, or on a separate line. """


class Employee:
""""""
pass


class Student:

def narendra(self):
pass

def kruthika(self):
pass


class Password_verification: pass






"""How to use class variable inside method
==> by using class name (class_name.class_variable)"""

class Employee:
count = 0 # class variable /attribute (Class variables will be shared with different objects created for the same class)
year = 2019 # class variable /attribute

def abc(self): # method
Employee.count += 1 # usage of class variable inside method==> class_name.class_variable
print("Present count value: ", Employee.count)
jaya = 300

def xyz(self): # method
Employee.count += 4 # usage of class variable inside method==> class_name.class_variable
print("Present count value: ", Employee.count)

def password_verification(self):
pass

"""class_variable will be shared among all the instances created by the user"""

# s1 = Employee() # I have created instance variable / object
# print(s1.count) # outside of the class ==> instance_variable.class_variable
# print(s1.year) # outside of the class ==> instance_variable.class_variable
# Employee.year = 2025 # class variable (so it will be shared among multiple instances for the same class)
# print(Employee.year)
#
# s1.abc() # object.method
# s1.xyz()
# print(s1.count)
#
# s2 = Employee()
# print(s2.count)
# print(s2.year) # printing class variable (it will display updated value)
# s2.abc()
# print(s2.count) # class_variable (count) was shared by 2nd instance also
#
# s3 = Employee()
# s3.abc()
# print(s3.count)
# s3.year=2029
# print(s3.year)



################## practice purpose ##############
def calc_factorial(x):
"""This is a recursive function
to find the factorial of an integer"""
if x == 1:
return 1
else:
return (x * calc_factorial(x-1))

Python Material - Part - 18 - Oops -1

 __author__ = "Narendra Boyina"

# -----------------------------------------------------------------------------
# Copyright (c) 2025 BR Technologies PVT LTD
# -----------------------------------------------------------------------------
"""
Topics to be covered in today's class:
--> Introduction of oops concept
--> Class syntax
--> Overview of Terminology

"""


"""
To understand the oops concept, we have to understand following concepts
1. what is class ?
Ans: Class is nothing but just blue-print.There is no use of class definition,
until unless you have created the instance/object for the particular class.

2. Difference between method and function ?
Ans: Function which is defined inside of the class is a method.
Function which is defined outside of the class is a Function.

3. What is Constructor method (def __init__(self)) ?
Ans: Constructor method (def __init__(self)) is a special kind of method,
as soon as you have created an object/ instance for the class then
automatically ___init__(self) method will be executed, without calling it.

how many no. of instances/objects you have created for a specific class
those many times __init__(self) will be executed without calling it

4. How many instances/objects we can create for single class?
N number of instances/ objects we can create for a single class.

5. What are the extra advantages of classes compared with functions?
Ans: 1. Grouping of function in the form of methods, provided with specific class name.
2. We can inherit the class into another class
3. We can perform multiple class related properties (Data hiding/abstraction/ method overriding/encapsulation...)


Syntax: class syntax also similar to function syntax

def fun_name([optional argument]):
['''doc_string''']
function_suite


class class_name:
['''doc_string''']
class suite
"""
"""
Overview of Terminology :
--> Variables --> We will declare variables outside of the function & outside of the class
--> arguments --> the variables declared inside the function definition called as arguments
--> attributes --> the variables declared inside the class definition called as attributes


--> class attributes are clasified into 2 types (1. class variables 2. instance variables)
--> By using dot notation, we can access Class attributes (class variables and instance variables) and methods.
But there is big difference between (class variables and instance variables)

"""
"""
Class variable − A variable that is shared by all instances of a class ((usually declared at the top))
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/ instance variable/object:− Instance variable that holds data associated with a class and its objects.
==================================================================================================================

Object − A unique instance of a data structure that is defined by its class.
An object comprises both attributes (class variables & instance variables) and methods.
"""

# company = "BR Techno Solutions" # company is a variable / global variable
# year = 2019 # age is a variable / global variable


def suresh(company, year): # company, year are arguments
print(company, year)



class Employee:
company = "BR Techno Solutions" # company is attribute / class variable
year = 2019 # company is attribute / class variable

def __init__(self, emp_name, employee_id): # emp_name, employee_id are attributes or instance variables
self.emp_name = emp_name
self.employee_id = employee_id
print("This was printed , because of you have created object for this class")
print("Name is {0} and employee_id is {1}".format(emp_name, employee_id))

def suresh(a, b, c): # a b, c are class attributes/ instance variables
print((a + b) * c)

def swetha(self, x=10):
print("Maha")


name = "Narendra" # variable/ global variable
number = "HM0002162" # variable/ global variable

suresh_obj = Employee(name, number) # creating object
ganesh_obj = Employee("ganesh", 23234) # creating object
# v_reddy_obj = Employee("venkatesh", 893234) # creating object
# print(id(suresh_obj),"\n",id(ganesh_obj),"\n", id(v_reddy_obj))


"""Accessing the attributes with the help of object and printing them outside of the class definition"""
# print(suresh_obj.emp_name) # calling class attributes (instance variable) from outside of class using object
# print(suresh_obj.employee_id) # calling class attributes(instance variable) from outside of class using object
# print(suresh_obj.company) # calling class attributes (class variable) from outside of class using object
# print(suresh_obj.year) # calling class attributes (class variable) from outside of class using object

""" we can modifiy the attribute's values from outside of the class by using object"""
# suresh_obj.emp_name = "Sai srinivas" # changing class attribute
# print(suresh_obj.emp_name)
# suresh_obj.emp_name = "venkat" # changing class attribute's value
# print(suresh_obj.emp_name) # changing class attribute's value
# suresh_obj.year = 2024 # changing class attribute's value
# print(suresh_obj.year)

""" We can add new attributes to the class from outside, by using Object"""
suresh_obj.salary = 88500 # we can add attribute (instance variable) from outside of class using object
suresh_obj.designation = "Team Lead" # we can add attribute (instance variable) from outside of class using object
print(suresh_obj.emp_name, suresh_obj.employee_id, suresh_obj.salary, suresh_obj.designation)


""" By using object, we can modify the attribute values """
suresh_obj.salary = 106000
print(suresh_obj.emp_name, suresh_obj.employee_id, suresh_obj.salary, suresh_obj.designation)

""" Creating a different object for the same class"""
naresh_obj = Employee("Naresh", "345678")
print(naresh_obj.emp_name)
print(naresh_obj.emp_name, naresh_obj.employee_id, naresh_obj.company, naresh_obj.year)

""" By using object, modifying existing attribute's value"""
naresh_obj.year = 2025
print(naresh_obj.year)

""" adding new attribute to 2nd object from outside of the class definition"""
naresh_obj.place = "Bangalore"
print(naresh_obj.place)

""" Creating different object for the same class"""
# meera_obj = Employee("Meera","HM530022")
# print(meera_obj.emp_name, meera_obj.employee_id,meera_obj.year,meera_obj.company)

""" observing memory locations for each object"""
# print(id(suresh_obj), id(naresh_obj), id(meera_obj))
# print(id(suresh_obj) != id(naresh_obj) != id(meera_obj) )
"""
Result:
=======
This was printed , because of you have created object for this class
Name is Narendra and Number is HM0002162
Narendra
HM0002162
Durga
Prasanth
Prasanth HM0002162 88500 Test Module Lead

after created an object, we can also access variables with that object
Ex:
a.name
a.number
"""

Author: Boyina Narendra

Supporting Author: M. Meera Sindhu

Request: If you find this information useful, please provide your valuable comments

Python Material - Part - 17 -Exception

 __author__ = "Narendra Boyina"

# -----------------------------------------------------------------------------
# Copyright (c) 2025 BR Technologies PVT LTD
# -----------------------------------------------------------------------------
"""
Topics to be covered in today's class:
--> what is exception ?
--> syntax of exception
--> Different types of exceptions in python
"""
"""
What is Exception?
When Python encounters an error, it raises an exception,
which can interrupt the normal flow of the program unless it is properly handled.

Common Causes of Exceptions:
--> Dividing by zero
--> Accessing a file that doesn’t exist
--> Referencing a variable that hasn’t been defined
--> Using the wrong type of data
"""

"""
Syntax
Here is simple syntax of try....except...else..finally blocks −

try:
We will implement the suspicious code (main logic) that may cause an error.
If an error occurs, it will be handled in the except block;
otherwise, the statements in the try block will execute as usual.
......................
except ExceptionI:
Except block handles errors from the try block and displays the error message on the console.
If there is ExceptionI, then execute this block of statements.
except ExceptionII:
If there is ExceptionII, then execute this block of statements.
......................
else:
If there is no exception then execute this block of statements.

finally:
The finally block allows you to execute code, regardless of the result of the try and except blocks.

"""


def add(a,b):
print(a+b)


# add(2.4, 4.2) # 2 float input values
# add(2, 4) # 2 integer input values
# add(-2, -4) # 2 negative integer input values
# add(2, 2.4) # 1 integer input value 1 float input value
# add("Polagani", "Subrahmanyam") # 2 string input values
# add("7", 3) # you have provided wrong values , please provide proper input values
# print("Narendra")
# print("Surendra")

# Exception handling for above logic


def add(a, b):
try:
print(a+b)
# except TypeError:
# print("user provided incorrect values")
# except ValueError:
# print("user provided wrong values")

# except TypeError as type_error_info:
# print(type_error_info)
# except ValueError as val_error:
# print(val_error)
# except AttributeError as err_info:
# print(err_info)
except Exception as error_info:
print(error_info)
else:
print("No exception occurred ")
finally:
print("this is finally block")
print("RAJ")

# add(2, 4)
# add(2, "MahaLakshmi")
# print("Narendra")
# print("Surendra")


"""
Example : 1
This example opens a file, writes content in the, file
and comes out gracefully because there is no problem at all −
"""

# fw = open("Narendra.txt", "r")
# fw.write("This is my test file for exception handling!!")

# try:
# fw = open("Narendra.txt", "r")
# fw.write("This is my test file for exception handling!!")
# except IOError as error_info:
# print(error_info)
# else:
# print ("Written content in the file successfully")
# fw.close()
#
# print("Jai")
# print("Abhishek")

"""
This produces the following result −

Written content in the file successfully
"""

"""
This example tries to open a file where you do not have the write permission, so it raises an exception −
"""

# try:
# fh = open("testfile.txt", "r")
# fh.write("Trying to write data in to the file")
# except Exception as file_error:
# print(file_error)
# else:
# print("Written content in the file successfully")
# finally:
# print("Jyothi")
# print("Kiran")

"""
This produces the following result −

Error: can't find file or read data
"""
# Argument of an Exception


def temp_convert(var):
try:
return int(var)
# except ValueError as jayanth:
# print("The argument does not contain numbers: ", jayanth)
# except TypeError as chandrika:
# print("**Type error:", chandrika)
except Exception as error_info :
print(error_info)
#
# Call above function here.
# x = temp_convert(12.5)
# x = temp_convert("12.5")
# y = temp_convert([1,2,4])
# print("value after converted is : {}".format(x))
# print(y)
# print("Manju")
# print("Narendra")



"""
Output
The argument does not contain numbers
invalid literal for int() with base 10: 'xyz'
Manju
"""


"""" Nested try block """

# try:
# fh = open("sai.txt", "r+")
# fh.write("This is outer try block")
# try:
# fh.seek(0,0)
# data = fh.read()
# print(data)
# fh.write("This is my test file for exception handling!!")
# except Exception as inner_error_info:
# print("inner exception occurred: ",inner_error_info)
# except Exception as outer_error_info:
# print ("outer exception occurred: ",outer_error_info)
# finally:
# print ("Going to close the file")
# print("Narendra")
# print("Meera")


"""Number of exceptions we can write in single program (Interpreter will handle based on Error)"""

# try:
# fh = open("testfile.txt", "r") #
# fh.write("This is my test file for exception handling!!")
# except IOError as Ierror:
# print ("if IO error occurred this statement will execute : ", Ierror)
# except ValueError as Verror:
# print("if Value error occurred this statement will execute :",Verror)
# except KeyError as x:
# print(x)
# else:
# print ("Written content in the file successfully")
# fh.close()
# finally:
# print("this is final block")

"""
How to handle any exception ? If we don't know which exception may occur
"""
# def add(a,b):
# try:
# print(a+b)
# except Exception as error_info:
# print(error_info)
#
#
# add(2, "Mahalakshmi")

daily_tasks = []

def read_lines(path):
try:
f_obj = open(path, "w")
for t in f_obj.readlines():
daily_tasks.append(t)
print(daily_tasks)
except Exception as Naziya:
print(Naziya)

# path = r"E:\Python Training\My Practice\BR_Techno_Solutions.txt"
# read_lines(path)
# print("Lakshmi")
# =====================================================================
"""
Different types of exceptions in python:

In Python, there are several built-in Python exceptions that can be raised when an error occurs during the execution of a program. Here are some of the most common types of exceptions in Python:

TypeError: This exception is raised when an operation or function is applied to an object of the wrong type, such as adding a string to an integer.
NameError: This exception is raised when a variable or function name is not found in the current scope.
IndexError: This exception is raised when an index is out of range for a list, tuple, or other sequence types.
KeyError: This exception is raised when a key is not found in a dictionary.
ValueError: This exception is raised when a function or method is called with an invalid argument or input, such as trying to convert a string to an integer when the string does not represent a valid integer.
AttributeError: This exception is raised when an attribute or method is not found on an object, such as trying to access a non-existent attribute of a class instance.
IOError: This exception is raised when an I/O operation, such as reading or writing a file, fails due to an input/output error.
ZeroDivisionError: This exception is raised when an attempt is made to divide a number by zero.
ImportError: This exception is raised when an import statement fails to find or load a module.
FilenotfoundError:
FilealreadyexistsError:
SyntaxError: This exception is raised when the interpreter encounters a syntax error in the code, such as a misspelled keyword, a missing colon, or an unbalanced parenthesis.

"""

Author: Boyina Narendra

Supporting Author: M. Meera Sindhu

Request: If you find this information useful, please provide your valuable comments



Python Built-in Exceptions

Exception

Cause of Error

AssertionError

Raised when assert statement fails.

AttributeError

Raised when attribute assignment or reference fails.

EOFError

Raised when the input() functions hits end-of-file condition.

FloatingPointError

Raised when a floating point operation fails.

GeneratorExit

Raise when a generator's close() method is called.

ImportError

Raised when the imported module is not found.

IndexError

Raised when index of a sequence is out of range.

KeyError

Raised when a key is not found in a dictionary.

KeyboardInterrupt

Raised when the user hits interrupt key (Ctrl+c or delete).

MemoryError

Raised when an operation runs out of memory.

NameError

Raised when a variable is not found in local or global scope.

NotImplementedError

Raised by abstract methods.

OSError

Raised when system operation causes system related error.

OverflowError

Raised when result of an arithmetic operation is too large to be represented.

ReferenceError

Raised when a weak reference proxy is used to access a garbage collected referent.

RuntimeError

Raised when an error does not fall under any other category.

StopIteration

Raised by next() function to indicate that there is no further item to be returned by iterator.

SyntaxError

Raised by parser when syntax error is encountered.

IndentationError

Raised when there is incorrect indentation.

TabError

Raised when indentation consists of inconsistent tabs and spaces.

SystemError

Raised when interpreter detects internal error.

SystemExit

Raised by sys.exit() function.

TypeError

Raised when a function or operation is applied to an object of incorrect type.

UnboundLocalError

Raised when a reference is made to a local variable in a function or method, but no value has been bound to that variable.

UnicodeError

Raised when a Unicode-related encoding or decoding error occurs.

UnicodeEncodeError

Raised when a Unicode-related error occurs during encoding.

UnicodeDecodeError

Raised when a Unicode-related error occurs during decoding.

UnicodeTranslateError

Raised when a Unicode-related error occurs during translating.

ValueError

Raised when a function gets argument of correct type but improper value.

ZeroDivisionError

Raised when second operand of division or modulo operation is zero.