Python OOP Exercises
Python OOP Exercises
Object Oriented
Programming Exercises Become a
Pro Developer
Python
Object Oriented
Programming Exercises
Become a Pro Developer
Edcorner Learning
Table of Contents
Introduction
1 Overview of Python OOPS
2 What in Python is OOPS?
3 Some of the Major Advantages of OOPS are:
4 Difference between procedural and object-oriented programming
5 Python's Class and Objects
6 What is a Class Definition in Python?
7 An __init__ method: What is it?
8 Creating a Class Object
9 What is Instance Methods with Example
10 The four core ideas of object-oriented programming are:
11 Inheritance
12 Super()
13 Polymorphism
14 Class Methods and polymorphism
15 Inheritance and Polymorphism
16 Encapsulation
17 A getter and a setter
18 Modifiers of Access
19 Abstraction
20 Important aspects of abstract classes
21 Certain noteworthy aspects of Abstract classes are:
22 OOPS's benefits in Python
Lets starts Python OOPS Programming Exercises
Module 1 Class Method - Decorator
Module 2 Static Method - Decorator
Module 3 Special Methods
Module 4 Inheritance
Module 5 Abstract Classes
Module 6 Miscelleanuoes Exercises
Introduction
4. Programming approach
POP adheres to programming from the top down. The top-down
method of programming focuses on dissecting a complex issue into
manageable units of code. The minor portions of the problems are
then resolved.
OOPS principles adhere to the Bottom-up method of programming.
The Bottom-Up method prioritises resolving the smaller issues at
their most fundamental level before incorporating them into a
comprehensive and entire solution.
Let's say you want to keep track of how many books you own. You
can easily do that by utilising a variable. Also possible is to
compute the sum of five numbers and save the result in a variable.
Simple values are intended to be stored in a variable using
primitive data structures like numbers, characters, and lists.
Consider your name, the square root of a number, or the quantity of
marbles (say).
But what if you need to keep a record of every employee in your
business? For instance, if you try to put all of your employees in a
list, you can later become confused about which index of the list
corresponds to which individual details (e.g. which is the name
field, or the empID or age etc.)
Even if you try to keep them in a dictionary, the entire codebase
will eventually become too complicated to manage. Therefore, we
employ Python Classes in these situations.
To create user-defined data structures in Python, use a class.
Classes set up functions, called "methods," that describe how an
object made from a class can behave and what actions it can take.
Classes and objects are the main topics covered by Python's OOPS
ideas.
Classes simplify the code by avoiding complicated codebases. It
accomplishes this by developing a model or design for how
everything ought to be defined. Any object that derives from the
class should have the characteristics or capabilities specified by this
clause.
Note:
Simple structural definition is all that a class does. It makes no
specific reference to anything or anyone. For instance, the class
HUMAN has attributes like name, age, gender, and city. It does not
identify any particular HUMAN, but it does describe the qualities
and capabilities that a HUMAN or an object of the HUMAN class
ought to have.
The term "object" refers to a class instance. It is the class's actual
implementation and is real.
A collection of data (variables) and methods (functions) that access
the data is referred to as an object. It is the actual class
implementation.
Take this example where Human is a class. This class only serves
as a template for what Human should be, not an actual
implementation. You could argue that the "Human" class only
makes logical sense.
However, "Edcorner" is a Human class object (please refer the
image given above for understanding). It follows that Edcorner was
built using the blueprint for the Human class, which holds the
actual data. Unlike "Human," "Edcorner" is a real person (which
just exists logically). He is a genuine person who embodies all the
characteristics of the class Human, including having a name, being
male, being 32 years old, and residing in Newyork. Additionally,
Edcorner uses all of the methods included in the Human class; for
example, Edcorner can walk, speak, eat, and sleep.
And many humans can be produced utilising the class Human
blueprint. For instance, by leveraging objects and the blueprint for
the class Human, we could generate many more persons.
Short Tip:
class = draught (suppose an architectural drawing). The Object is a
real item that was created using the "blueprint" (suppose a house).
An instance is a representation of the item that is virtual but not a
true copy.
No memory is allotted to a class when it is defined; just the object's
blueprint is produced. Memory allocation only takes place during
object or instance creation. The actual data or information is
contained in the object or instance.
6 What is a Class Definition in Python?
Python classes are defined using the word class, which is then
followed by the class name and a colon.
Syntax:
Below the class definition, indented code is regarded as a
component of the class body.
In a method named init, the qualities that all Human objects must
possess are specified (). When a new Human object is formed,
__init__() assigns the values we supply inside the object's
properties to set the object's initial state. In other words, each new
instance of the class is initialised via __init__(). Any number of
parameters can be passed to __init__(), but self is always the first
parameter.
The self parameter contains a reference to the active class instance.
This means that we can access the data of an object's variables by
using the self argument, which corresponds to the address of the
current object of a class.
Since this self points to the address of each individual object and
returns its corresponding value, even if there are 1000 instances
(objects) of a class, we can always access each of their unique data.
Let's look at how the Human class defines __init__():
We use the self variable three times in the body of. init__() for the
following purposes:
self.name = 'name' creates the name attribute and sets the name
parameter's value as its value.
self.age = The age attribute is created and given the value of the
age parameter that was supplied.
self.gender = The gender parameter value is produced and assigned
to the gender attribute.
In Python, there are two categories of attributes:
Class attribute number 1:
These variables apply to all instances of the class equally. For each
new instance that is created, they do not have new values. Just after
the class definition, they are defined.
In this case, whatever object we create will have a fixed value for
the species.
2. Instance Information:
The variables that are defined inside of any class function are
known as instance attributes. Every instance of the class has a
unique value for the instance attribute. These values rely on the
value that was supplied when the instance was created.
The instance attributes in this case are name, age, and gender.
When a new instance of the class is created, they will have
different values.
8 Creating a Class Object
Inheritance
Encapsulation
Polymorphism
Abstraction of data.
People frequently tell newborns that they have face features that
resemble those of their parents or that they have inherited particular
traits from their parents. It's possible that you've also observed that
you share a few characteristics with your parents.
The real-world situation is fairly similar to inheritance as well.
However, in this case, the "parent classes"' features are passed
down to the "child classes." They are referred to as "properties" and
"methods" here, along with the qualities they inherit.
A class can derive its methods and attributes from another class's
by using the process known as inheritance. Inheritance is the
process of a child class receiving the properties of a parent class.
The Parent class is the class from which the properties are
inherited, and the Child class is the class from which the properties
are inherited.
As we did in our previous examples, we define a typical class.
After that, we may declare the child class and provide the name of
the parent class it is descended from in parenthesis.
The parent class Human is inherited by the child class Boy in the
example above. Because Boy is inheriting from Human, we can
access all of its methods and properties when we create an instance
of the Boy class.
In the Boy class, a method called schoolName has also been
defined. The parent class object is unable to access the method
schoolName. The schoolName method can, however, be called by
making a child class object (Boy).
Let's look at the problem we run into if we try to use the object
from the parent class to invoke the methods of a child class.
Therefore, the AttributeError: 'Human' object has no
attribute'schoolName' is returned in this case. because it is not
possible for child classes to access parent class data and properties.
12 Super()
The parent class is referred to in the inheritance-related method
super(). It can be used to locate a certain method in a superclass of
an object. It serves a very important purpose. Let's examine its
operation —
The super function's syntax is as follows. After the super()
keyword, we write the name of the parent class function we want to
refer to.
Here, the classes Human and Girl have definitions for the Code()
method. But as you can see, each method has a separate
implementation. The Code technique in Human class reads "I can
Code," whereas the Code method in Girl class reads "I can teach."
So let's call the Code technique from the child class to the parent
class.
As you can see, we are using super to call the Code method at line
19. ().
Code(). This will invoke the Human class' Code method. Thus, "I
can Code" is printed. Nevertheless, Code() was already
implemented in Girl (at line 15).
If a method with the same name already exists in the subclass,
super() will still call the method in the superclass.
13 Polymorphism
Let's say you are using your phone to browse the Instagram feeds.
You opened Spotify and began playing your favourite song because
you suddenly had the urge to listen to some music as well. After a
while, you received a call, so you paused whatever you were doing
in the background to answer it. Your friend called and requested
that you text them a certain person's phone number. So you sent
him the phone number through SMS and carried on with your
tasks.
Have you picked up on anything? With just one device—your
mobile phone—you could surf through feeds, listen to music, take
and make phone calls, and message.
Therefore, polymorphism is comparable to that. Poly means
numerous, and morph denotes different forms. Therefore,
polymorphism as a whole refers to something with various forms.
Or "something" that, depending on the circumstance, can exhibit a
variety of behaviours.
In OOPS, polymorphism describes functions with the same names
but different behaviours. Alternatively, a different function
signature with the same function name (parameters passed to the
function).
All of a child class's properties are inherited from the parent class's
methods. But occasionally, it tries to change the techniques by
adding its own implementation. In Python, there are many different
ways to use polymorphism.
An illustration of an inbuilt polymorphic function
An example of an inbuilt polymorphism function is len(). It will
just compute the value and return because we can use it to calculate
the length of various kinds like strings, lists, tuples, and
dictionaries.
Here, the len function was given a string, list, and dictionary, and it
computed the answer. It serves as an illustration of an inbuilt
polymorphic function.
You must have encountered pill forms for medications where the
entire contents are kept sealed inside the capsule’s lid. In essence, a
capsule contains many drug combinations.
In programming, the variables and the methods are similarly kept
in a container known as a “class”! Yes, we have learned a lot about
classes in Python, and we are already aware that every variable and
function we create in OOP stays inside the class.
Encapsulation is the term used in Python to describe the act of
combining data with the matching methods (behaviour) into a
single entity.
Encapsulation, then, is a programming approach that ties the class’s
variables and methods together and makes it impossible for other
classes to access them. It is an example of an OOPS concept in
Python.
Security is possible via encalpsulation. It protects the data from
outside access. By encapsulating an object or piece of information,
a company can prevent clients or other unauthorised individuals
from accessing it without permission.
17 A getter and a setter
You most likely use a laptop, phone, or tablet to read this book.
While reading it, you are also presumably taking notes, underlining
key passages, and possibly saving some information to your
personal files. All you can see when you read this is a "screen" with
the data that is being displayed to you. You just see the keyboard's
keys as you type, so you don't have to worry about internal
subtleties like how pushing a key can cause that word to appear
onscreen. Alternatively, how pressing a button on your screen may
launch a new tab!
Therefore, whatever we may see in this situation is abstract. We
can only see the outcome it is producing and not the inside details
(which actually matters to us).
Similar to this, abstraction only reveals the functions that anything
possesses while concealing any implementations or internal details.
Abstraction's major objective is to conceal background information
and any extraneous data implementation so that people only see
what they need to see. It aids in managing the codes' complexity.
20 Important aspects of abstract classes
Python's support for OOPS ideas has many benefits that make
it suitable for the development of significant software. Let's
examine a couple of them:
Effective problem-solving is possible because we create
classes that do the necessary actions for each mini-problem.
The next problem can be solved even more quickly because
we can reuse those classes.
flexibility in having different versions of the same class
thanks to polymorphism
high level of code complexity was reduced through
abstraction.
By encapsulating, high security and data privacy are achieved.
code reuse caused by a child class's inheritance of parent class
properties.
Instead than sifting through hundreds of lines of code to locate
a single problem, modularity of programming makes
debugging simple.
Lets starts Python OOPS Programming Exercises
Module 1 Class Method - Decorator
1. Using the classmethod class (do it in the standard way) implement a class
named Person that has a class method named show_details() which displays
the following text to the console:
'Running from Person class.'
Try to pass the class name using the appropriate attribute of the Person class.
In response, call the show_details() class method.
Expected result:
Running from Person class.
class Container:
@classmethod
def show_details(cls):
print(f'Running from {cls.__name__} class.')
class Person:
instances = []
def __init__(self):
Person.instances.append(self)
@classmethod
def count_instances(cls):
return len(Person.instances)
Module 2 Static Method - Decorator
Solution:
import time
class Container:
def get_current_time():
return time.strftime('%H:%M:%S', time.localtime())
get_current_time = staticmethod(get_current_time)
7. Define a Container class that has a static method (use the @staticmethod
decorator) named get_current_time() returning the current time in the format
'%h:%m:%s' , e.g. '09:45:10' .
Tip: Use the built-in time module.
Solution :
import time
class Container:
@staticmethod
def get_current_time():
return time.strftime('%H:%M:%S', time.localtime())
import uuid
class Book:
import uuid
class Book:
@staticmethod
def get_id():
return str(uuid.uuid4().fields[-1])[:6]
Expected result:
Book(title=' Python Object Oriented Programming Exercises Volume 2',
author='Edcorner Learning')
import uuid
class Book:
Solution:
import uuid
class Book:
def __repr__(self):
return f"Book(title='{self.title}', author='{self.author}')"
@staticmethod
def get_id():
return str(uuid.uuid4().fields[-1])[:6]
book1 = Book(' Python Object Oriented Programming Exercises
Volume 2', author='Edcorner Learning')
print(book1)
Module 3 Special Methods
10. Define a Person class that takes two bare attributes: fname (first
name) and Iname (last name).
Then implement the _repr_ ( ) special method to display a
formal representation of the
Person object as shown below:
[IN]: person = Person('John', 'Doe')
[IN]: print(person)
[OUT]: Person(fname='John', lname=’Doe’)
Create an instance of the Person class with the given attributes:
fname = 'Mike'
• lname = 'Smith'
and assign it to the variable person. In response, print the person
instance to the console.
Expected result:
Person(fname='Mike’, lname='Smith')
Solution:
def __repr__(self):
return f"Person(fname='{self.fname}', lname='{self.lname}')"
Solution:
Solution:
class Vector:
def __repr__(self):
return f'Vector{self.components}'
def __str__(self):
return f'{self.components}'
v1 = Vector(-3, 4, 2)
print(v1)
14. An implementation of the Vector class is given. Implement the
_len_ ( ) special method to return the number of vector
coordinates.
Example:
[IN]: vl = Vector(3, 4, 5)
[IN]: print(len(vl))
[Out]: 3
Create a vector from the RA3 space with coordinates: (-3,4,2) and
assign it to the variable v7. In response, print the number of coordinates
of this vector using the built-in len() function.
Expected result:
3
class Vector:
def __init__(self, *components):
self.components = components
def __repr__(self):
return f'Vector{self.components}'
def __str__(self):
return f'{self.components}'
15. An implementation of the Vector class is given. Implement the
_bool_( ) special method to return the logical value of vector:
• False in case the first coordinate is zero
• on the contrary True
If the user doesn't pass any argument, return the logical value False.
Example
[IN]: vl = Vector(0, 4, 5)
[IN]: print(bool(vl))
[Out]: False
Then create the following instances:
• vl = Vector()
• v2 = Vector(3, 2)
v3 = Vector(0, -3, 2)
v4 = Vector(5, 0, -1)
In response, print the logical value of the given instances to the console.
Expected result:
False
True
False
True
class Vector:
def __repr__(self):
return f'Vector{self.components}'
def __str__(self):
return f'{self.components}'
def __len__(self):
return len(self.components)
16. An implementation of the Vector class is given. Create the following
instances of this class:
• vl = Vector(4, 2)
• v2 = Vector(-l, 3)
Then try to add these instances, i.e. perform the operation v1 + v2 . If there is
an error, print the error message to the console. Use a try ... except ... clause
in your solution.
Expected result:
unsupported operand type(s) for +: 'Vector' and 'Vector'
class Vector:
def __repr__(self):
return f"Vector{self.components}"
def __str__(self):
return f'{self.components}'
def __len__(self):
return len(self.components)
17. An implementation of the Vector class is given. Implement the _add_( ) special method to
add Vector instances (by coordinates). For simplicity, assume that the user adds vectors of the same
length. Then create two instances of the Vector class:
vl = Vector(4, 2)
v2 = Vector(-l, 3)
and perform the addition of these vectors. Print the result to the console.
Expected result:
(3,5)
class Vector:
def __init__(self, *components):
self.components = components
def __repr__(self):
return f'Vector{self.components}'
def __str__(self):
return f'{self.components}'
def __len__(self):
return len(self.components)
18. An implementation of the Vector class is given. Create the following
instances of this class:
• vl = Vector(4, 2)
• v2 = Vector(-l, 3)
Then try to subtract these instances (perform the v1 - v2 operation). If there is
an error, print the error message to the console. Use a try ... except ... clause
in your solution.
Expected result:
unsupported operand type(s) for 'Vector' and 'Vector'
class Vector:
def __repr__(self):
return f"Vector{self.components}"
def __str__(self):
return f'{self.components}'
def __len__(self):
return len(self.components)
def __repr__(self):
return f'Vector{self.components}'
def __str__(self):
return f'{self.components}'
def __len__(self):
return len(self.components)
def __add__(self, other):
components = tuple(x + y for x, y in zip(self.components,
other.components))
return Vector(*components)
Soluton:
20. An implementation of the Vector class is given. Implement the
_mui ( ) special method that allows you to multiply Vector
instances (by coordinates). For simplicity, assume that the user
multiplies vectors of the same length. Then create two instances of this
class:
• vl = Vector(4, 2)
• v2 = Vector(-l, 3)
and perform the multiplication of these vectors. Print the result to the
console.
Expected result:
(-4,6)
class Vector:
def __repr__(self):
return f'Vector{self.components}'
def __str__(self):
return f'{self.components}'
def __len__(self):
return len(self.components)
def __repr__(self):
return f'Vector{self.components}'
def __str__(self):
return f'{self.components}'
def __len__(self):
return len(self.components)
def __repr__(self):
return f'Vector{self.components}'
def __str__(self):
return f'{self.components}'
def __len__(self):
return len(self.components)
v1 = Vector(4, 2)
v2 = Vector(-1, 4)
print(v1 / v2)
def __repr__(self):
return f'Vector{self.components}'
def __str__(self):
return f'{self.components}'
def __len__(self):
return len(self.components)
Solution:
class Vector:
def __repr__(self):
return f'Vector{self.components}'
def __str__(self):
return f'{self.components}'
def __len__(self):
return len(self.components)
v1 = Vector(4, 2)
v2 = Vector(-1, 4)
print(v1 // v2)
23. The following Doc class is implemented for storing text documents.
Implement the _add_ ( ) special method to add Doc instances with a
space character.
Example:
[IN]: docl = Doc('Object')
[IN]: doc2 = Doc('Oriented')
[IN]: print(docl + doc2)
def __repr__(self):
return f"Doc(string='{self.string}')"
def __str__(self):
return f'{self.string}'
24. The following Hashtag class is implemented for storing text
documents - hashtags. Implement the _add_ () special method
to add (concatenate) Hashtag instances using a space character as
shown below (take into account the appropriate number of ■ # ■
characters at the beginning of the new object).
Example:
[IN]: hashtagl = Hashtag('sport')
[IN]: hashtag2 = Hashtag('travel1) [IN]: print(hashtagl + hashtag2)
[OUT]: »sport »travel
Then create three Hashtag instances for the following text documents:
• python
• developer
• oop
In response, print the result of adding these instances.
Expected result:
#python #developer #oop
class Hashtag:
def __repr__(self):
return f"Hashtag(string='{self.string}')"
def __str__(self):
return f'{self.string}'
Solution:
25. The following Doc class is implemented for storing text documents.
Implement the _eq_( )special method to compare Doc instances. Class
instances are equal when they have identical string attribute values.
Example:
[IN]: docl = Doc('Finance')
[IN]: doc2 = Doc('Finance')
[IN]: print(docl == doc2)
[OUT]: True
Then create two instances of the Doc class for the following
documents:
• 'Python'
• '3.8'
In response, print the result of comparing these instances.
Expected result:
False
class Doc:
def __repr__(self):
return f"Doc(string='{self.string}')"
def __str__(self):
return f'{self.string}'
26. The following Doc class is implemented for storing text documents.
Implement the _it_( )
special method to compare Doc instances. A class instance is 'smaller1
than another instance when the string attribute is shorter.
Example:
[IN]: docl = Doc('Finance')
[IN]: doc2 = Doc('Education')
[IN]: print(docl < doc2)
[OUT]: True
Then create two instances of the Doc class for the following
documents:
• 'sport'
• 'activity'
and assign to the variables:
doc1
doc2
In response, print the result of comparing these instances (perform
doc1 < doc2 ).
Expected result:
True
class Doc:
def __repr__(self):
return f"Doc(string='{self.string}')"
def __str__(self):
return f'{self.string}'
Solution:
27. The following Doc class is implemented for storing text documents.
Implement the _iadd_() special method to perform extended
assignments. Concatenate two instances with the string ‘ & ‘
Example:
[IN]:
[IN]:
[IN]:
docl = Doc(1 Finance')
doc2 = Doc('Accounting1)
docl += doc2
[IN]: print(docl)
[OUT]: Finance & Accounting
Then create two instances of the Doc class for the following
documents:
• 'sport'
• 'activity'
and assign according to the variables:
• docl
doc2
Perform extended assignment
• docl + = doc2
Expected result:
sport & activity
class Doc:
def __repr__(self):
return f"Doc(string='{self.string}')"
def __str__(self):
return f'{self.string}'
Solution:
28. The Book class is given. Implement the _str _() method to display
an informal
representation of a Book instance (see below).
Example:
[IN]: bookl = Book('Python OOPS Vol2', 'Edcorner Learning’)
[IN]: print(bookl)
[OUT]: Book ID: 214522 | Title: Python OOPS Vol2 | Author:
Edcorner Learning
Then create an instance named book with arguments:
• title= ‘Python OOPS Vol2’
• author='Edcorner Learning’
In response, print the instance to the console.
Expected result:
Book ID: 1234 | Title: Python OOPS Vol2 | Author: Edcorner
Learning
Note: The Book ID value may vary.
import uuid
class Book:
def __repr__(self):
return f"Book(title='{self.title}', author='{self.author}')"
@staticmethod
def get_id():
return str(uuid.uuid4().fields[-1])[:6]
Solution:
Module 4 Inheritance
29. The Container class was implemented. Implement two simple classes
inheriting from the class Container with names respectively:
• PlasticContainer
• MetalContainer
class Container:
pass
Solution:
class Container:
pass
class PlasticContainer(Container):
pass
class MetalContainer(Container):
pass
class Container:
pass
class PlasticContainer(Container):
pass
class MetalContainer(Container):
pass
class CustomContainer:
pass
Solution:
class Container:
pass
class PlasticContainer(Container):
pass
class MetalContainer(Container):
pass
class CustomContainer:
pass
print(issubclass(PlasticContainer, Container))
print(issubclass(MetalContainer, Container))
print(issubclass(CustomContainer, Container))
Expected result:
Vehicle(category='land vehicle')
LandVehicle(category='land vehicle1)
AirVehicle(category='air vehicle1)
class Vehicle:
Expected result:
Vehicle -> land vehicle
LandVehlcle -> land vehicle
AlrVehlcle -> air vehicle
class Vehicle:
def __init__(self, category=None):
self.category = category if category else 'land vehicle'
class LandVehicle(Vehicle):
pass
class AirVehicle(Vehicle):
class Vehicle:
34. The Vehicle and Car classes are listed below. Implement a method named
dispiay_attrs() in the base class Vehicle, which displays the instance
attributes and their values. For example, for the Vehicle class:
vehicle = Vehlcle('BMW', 'red', 2020) vehicle.dlsplay_attrs()
brand -> BMW
color -> red
year -> 2020
And for the Car class:
car = Car(‘BMW’, 'red', 2020, 190) car.dlsplay_attrs()
brand -> BMW color -> red
year -> 2020
horsepower -> 190
Then create an instance of the Car class named car with the attribute values: 1
Opel ', 'black', 2018, 160
In response, call dispiay_attrs( ) on the car instance.
Expected result:
brand -> Opel
color -> black
year -> 2018
horsepower -> 160
class Vehicle:
class Car(Vehicle):
def __init__(self, brand, color, year, horsepower):
super().__init__(brand, color, year)
self.horsepower = horsepower
Solution:
35. The Vehicle and Car classes are listed below. Extend the
dispiay_attrs() method in the Car class so that the following
information is displayed before displaying the attributes: ' calling from
class: Car' and then the rest of the attributes with their values. Use super
() for this. For example, for the Car class:
car = Car('BMW', 'red', 2020, 190) car.dlsplay_attrs()
returns:
Calling from class: Car brand -> BMW
color -> red
year -> 2020
horsepower ->
190
Then create an instance of the class Car named car with the attribute
values: ' BMW’
'black', 2018, 260
In response, call display_attrs( ) on the car instance.
Expected result:
Calling from class: Car
brand -> BMW
color -> black
year -> 2018
horsepower -> 260
class Vehicle:
def display_attrs(self):
for attr, value in self.__dict__.items():
print(f'{attr} -> {value}')
class Car(Vehicle):
Solution:
36. Implement simple classes with the following structure:
• Container
• TemperatureControlledContainer • RefrigeratedContainer
The TemperatureControlledContainer class inherits from the Container class
and the RefrigeratedContainer class inherits from
TemperatureControlledContainer.
Solution:
class Container:
pass
class TemperatureControlledContainer(Container):
pass
class RefrigeratedContainer(TemperatureControlledContainer):
pass
class Department:
pass
40. The following classes are defined. Add the _init_() method to the Person
class, which sets three attributes:
• firstname
• lastname
• age
Then create an instance of the Worker class passing the following arguments:
• 'John'
'Doe'
• 35
In response, print the value of the _dict_ attribute of this instance.
Expected result:
{‘first_name’ : 'John', 'last_name': 'Doe', 'age': 35}
class Person:
pass
class Department:
pass
class Worker(Person, Department):
pass
Solution:
41. The following classes are defined. Add a init ( ) method to the
Department class that sets
the following attributes:
• deptname (department name)
• short_dept_name (department short name)
Then create an instance of the Department class with arguments:
• 'Information Technology'
• 'IT'
In response, print the value of the _dict_ attribute of this instance.
Expected result:
{'dept_name': 'Information Technology', 'short_dept_name': 'IT'}
class Person:
Solution:
42. The following classes are defined. Add the _init_( ) method to the Worker
class to set all the attributes from the Person and Department classes.
Then create an instance of the Worker class passing the following arguments:
• 'John'
• 'Doe'
• 30
• 'Information Technology’
• 'IT'
In response, print the value of the _dict_ attribute of this instance.
•
Expected Result:
{'first_name': 'John', 'last_name': 'Doe', 'age': 30, 'dept_name':
'Information Technology', 'short_dept_name': 'IT'}
class Person:
self.short_dept_name = short_dept_name
class Worker(Person, Department):
pass
Solution:
class Person:
Solution:
43. The following classes are defined. Display the MRO - Method
Resolution Order for the Worker class.
Note: The solution that the user passes is in a file named exercise.py,
while the checking code (which is invisible to the user) is executed
from a file named evaluate.py from the level where the classes are
imported. Therefore, instead of the name of the module
_main_ , the response will be the name of the module in which
this class is implemented, in this case exercise .
Expected result:
[<class 'exercise.Worker’>, <class 'exercise.Person'>, <class
'exercise.Departnent’, <class 'object’>]
class Person:
Solution:
class Person:
def __init__(self, first_name, last_name, age):
self.first_name = first_name
self.last_name = last_name
self.age = age
class Department:
def __init__(self, dept_name, short_dept_name):
self.dept_name = dept_name
self.short_dept_name = short_dept_name
class Worker(Person, Department)
Solution:
def area(self):
return self.a * self.a
Solution:
from abc import ABC, abstractmethod
class Figure(ABC):
@abstractmethod
def area(self):
pass
@abstractmethod
def perimeter(self):
pass
class Square(Figure):
def area(self):
return self.a * self.a
def perimeter(self):
return 4 * self.a
square = Square(10)
print(square.area())
print(square.perimeter())
46. Create an abstract class named Taxpayer. In the _init_() method set an
instance attribute
(without validation) called salary. Then add an abstract method called
calculate_tax() (use the @abstractmethod decorator).
Solution:
from abc import ABC, abstractmethod
class TaxPayer(ABC):
def __init__(self, salary):
self.salary = salary
@abstractmethod
def calculate_tax(self):
pass
class TaxPayer(ABC):
def __init__(self, salary):
self.salary = salary
@abstractmethod
def calculate_tax(self):
pass
Solution:
from abc import ABC, abstractmethod
class TaxPayer(ABC):
@abstractmethod
def calculate_tax(self):
pass
class StudentTaxPayer(TaxPayer):
def calculate_tax(self):
return self.salary * 0.15
student = StudentTaxPayer(40000)
print(student.calculate_tax())
@abstractmethod
def calculate_tax(self):
pass
class StudentTaxPayer(TaxPayer):
def calculate_tax(self):
return self.salary * 0.15
Solution:
from abc import ABC, abstractmethod
class TaxPayer(ABC):
@abstractmethod
def calculate_tax(self):
pass
class StudentTaxPayer(TaxPayer):
def calculate_tax(self):
return self.salary * 0.15
class DisabledTaxPayer(TaxPayer):
def calculate_tax(self):
return min(self.salary * 0.12, 5000.0)
disabled = DisabledTaxPayer(50000)
print(disabled.calculate_tax())
49. An implementation of the Taxpayer abstract class is given.
Create a class derived from the TaxPayer class named WorkerTaxPayer
that implements the caicuiate_tax( ) method that calculates the tax
value according to the rule:
• up to the amount of 80,000 -> 17% tax rate
• everything above 80,000 -> 32% tax rate
Then create two instances of WorkerTaxPayer named workerl and
worker2 and salaries of 70,000 and 95,000 respectively. In response, by
calling caicuiate_tax() print the calculated tax for both instances to the
console.
Expected result:
11900.0
18400.0
from abc import ABC, abstractmethod
class TaxPayer(ABC):
def __init__(self, salary):
self.salary = salary
@abstractmethod
def calculate_tax(self):
pass
class StudentTaxPayer(TaxPayer):
def calculate_tax(self):
return self.salary * 0.15
class DisabledTaxPayer(TaxPayer):
def calculate_tax(self):
return self.salary * 0.12
Solution:
from abc import ABC, abstractmethod
class TaxPayer(ABC):
@abstractmethod
def calculate_tax(self):
pass
class StudentTaxPayer(TaxPayer):
def calculate_tax(self):
return self.salary * 0.15
class DisabledTaxPayer(TaxPayer):
def calculate_tax(self):
return self.salary * 0.12
class WorkerTaxPayer(TaxPayer):
def calculate_tax(self):
if self.salary < 80000:
return self.salary * 0.17
else:
return 80000 * 0.17 + (self.salary - 80000) * 0.32
worker1 = WorkerTaxPayer(70000)
worker2 = WorkerTaxPayer(95000)
print(worker1.calculate_tax())
print(worker2.calculate_tax())
def calculate_tax(self):
if self.salary < 80000:
return self.salary * 0.17
else:
return 80000 * 0.17 + (self.salary - 80000) * 0.32
Solution:
from abc import ABC, abstractmethod
class TaxPayer(ABC):
def __init__(self, salary):
self.salary = salary
@abstractmethod
def calculate_tax(self):
pass
class StudentTaxPayer(TaxPayer):
def calculate_tax(self):
return self.salary * 0.15
class DisabledTaxPayer(TaxPayer):
def calculate_tax(self):
return self.salary * 0.12
class WorkerTaxPayer(TaxPayer):
def calculate_tax(self):
if self.salary < 80000:
return self.salary * 0.17
else:
return 80000 * 0.17 + (self.salary - 80000) * 0.32
tax_payers = [StudentTaxPayer(50000),
DisabledTaxPayer(70000),
WorkerTaxPayer(68000), WorkerTaxPayer(120000)]
for tax_payer in tax_payers:
print(tax_payer.calculate_tax())
Module 6 Miscelleanuoes Exercises
51. The people list is given. Sort the objects in the people list ascending by
age. Then print the name and age to the console as shown below.
Expected result:
Alice-> 19
Tom ->25
Mike -27
John -> 29
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
people = [Person('Tom', 25), Person('John', 29),
Person('Mike', 27), Person('Alice', 19)]
Solution:
52. The following Point class is given. Implement a reset ( ) method that
allows you to set the values of the x and y attributes to zero. Then create an
instance of the Point class with coordinates (4, 2) and print it to the console.
Call the reset ( ) method on this instance and print the instance to the console
again.
Expected result:
Point(x=4, y=2)
Point(x=0, y=0)
class Point:
def __repr__(self):
return f"Point(x={self.x}, y={self.y})"
Solution:
def __repr__(self):
return f"Point(x={self.x}, y={self.y})"
def reset(self):
self.x = 0
self.y = 0
Solution:
54. Implement a class called Note that describes a simple note. When creating
Note objects, an instance attribute called content will be set with the contents
of the note. Also add instance attribute called creationjime that stores the
creation time (use the given date format: '%m-%d- %Y %H:%M:%S' ).
Next, create two instances of the Note class named notel and note2, and
assign the following contents:
'My first note.'
'My second note.'
Solution:
import datetime
class Note:
55. The Note class is given. Implement a find( ) method that checks if a
given word is in the note (case sensitive). The method should return
True or False, respectively.
Then create an instance named notel with the contents of the note:
'Object Oriented Programming in Python.'
On the notel instance call the find() method to check if the note
contains the following words:
• 'python'
• 'Python'
Print the result to the console.
Expected result:
False
True
import datetime
class Note:
Solution:
56. The Note class is given. Implement a find( ) method that checks if a
given word is in the note (case insensitive). The method should return
True or False, respectively.
Then create an instance named notel with the contents of the note:
'Object Oriented Programming in Python.'
On the note7 instance call the find() method to check if the note
contains the following words:
'python'
'Python'
Print the result to the console.
Expected result:
True
True
import datetime
class Note:
def __init__(self, content):
self.content = content
self.creation_time = datetime.datetime.now().strftime('%m-%d-%Y
%H:%M:%S')
Solution:
Solution:
58. Implementations of the Note and Notebook class are given.
Implement a method named dispiay_notes( ) in the Notebook class to
display the content of all notes of the notes instance attribute to the
console.
Create an instance of the Notebook class named notebook. Then, using
the new_note() method add two notes to the notebook with the
following content:
• 'My first note.'
• 'My second note.'
In response, call dispiay_notes() method on the notebook instance.
Expected result:
My first note.
My second note.
import datetime
class Note:
def __init__(self, content):
self.content = content
self.creation_time = datetime.datetime.now().strftime('%m-%d-
%Y %H:%M:%S')
def __repr__(self):
return f"Note(content='{self.content}')"
def find(self, word):
return word.lower() in self.content.lower()
class Notebook:
def __init__(self):
self.notes = []
def new_note(self, content):
self.notes.append(Note(content))
Solution:
Solution:
59. Implementations of the Note and Notebook class are given. Implement a
method called search() in the Notebook class that allows you to return a list
of notes containing a specific word (passed as an argument to the method,
case insensitive). You can use the Note.find method for this.
Create an instance of the Notebook class named notebook. Then, using the
new_note() method add notes to the notebook with the following content:
• 'Big Data'
• 'Data Science'
• 'Machine Learning'
In response, call the search() method on the notebook instance looking for
notes that contain the Word 'data' .
Expected result:
[Note(content='Big Data'), Note(content='Data Science')]
import datetime
class Note:
def __repr__(self):
return f"Note(content='{self.content}')"
def __init__(self):
self.notes = []
def new_note(self, content):
self.notes.append(Note(content))
def display_notes(self):
for note in self.notes:
print(note.content)
def search(self, value):
return [note for note in self.notes if note.find(value)]
notebook = Notebook()
notebook.new_note('Big Data')
notebook.new_note('Data Science')
notebook.new_note('Machine Learning')
print(notebook.search('data'))
60. Implement a class named Client which has a class attribute named
all_clients (as a list). Then the _init_( ) method sets two instance
attributes (no validation):
• name
• email
Add this instance to the alLclients list (Client class attribute). Also add a
_repr_( ) method
the Client class (see below).
Create three clients by executing the following code:
Clientl = Client(‘Tom’, ‘[email protected]’)
client2 = Client(‘Donald', ‘[email protected]’)
client3 = Client('Mike’, ‘[email protected]’)
In response, print the all_cients attribute of the Client class.
Expected Result:
[Client(name='Tom', email='[email protected]'),
Client(name='Donald', email='[email protected]'), Client(name='Mike',
email='[email protected]')]
Solution:
class Client:
all_clients = []
61. The Client class is implemented. Note the class attribute all_clients. Try
to implement a special class extending the built-in list class called ClientList,
which in addition to the standard methods for the built-in class list will have a
search_emaii() method that allows you to return a list of Client class
instances containing the text (value argument) in the email address.
For example, the following code:
Clientl = Client(‘Tom’, ‘[email protected]’)
client2 = Client(‘Donald', ‘[email protected]’)
client3 = Client('Mike’, ‘[email protected]’)
client4 = Client(1 Lisa1, '[email protected]' )
print(Client.all_clients.search_email('sales'))
class ClientList(list)
def search_email(self, value):
pass
class Client:
all_clients = ClientList()
def __init__(self, name, email):
self.name = name
self.email = email
Client.all_clients.append(self)
def __repr__(self):
return f"Client(name='{self.name}', email='{self.email}')"
Solution:
class ClientList(list):
class Client:
all_clients = ClientList()
def __init__(self, name, email):
self.name = name
self.email = email
Client.all_clients.append(self)
def __repr__(self):
return f"Client(name='{self.name}', email='{self.email}')"
class ClientList(list):
class Client:
all_clients = ClientList()
def __repr__(self):
return f"Client(name='{self.name}', email='{self.email}')"
Solution:
63. The Client class is implemented. The following four instances of the
Client class:
class ClientList(list):
class Client:
all_clients = ClientList()
def __repr__(self):
return f"Client(name='{self.name}', email='{self.email}')"
client1 = Client('Tom', '[email protected]')
client2 = Client('Donald', '[email protected]')
client3 = Client('Mike', '[email protected]')
client4 = Client('Lisa', '[email protected]')
Solution:
64. Create a class named CustomDict that extends the built-in diet
class. Add a method named is_any_str_vaiue() that returns a boolean
value:
• True in case the created dictionary contains at least one value of
str type
• otherwise False.
Example I:
[IN]: cd = CustonDict(python=’mid')
[IN]: print(cd.ls_any_str_value())
returns:
[OUT]: True
Example II:
[IN]: cd = CustomDict(price=119.99)
[IN]: print(cd.ls_any_str_value())
returns:
[OUT]: False
You only need to implement the CustomDict class.
Solution:
class CustomDict(dict):
def is_any_str_value(self):
flag = False
for key in self:
if isinstance(self[key], str):
flag = True
break
return flag
65. Create a class named StringListOnly that extends the built-in list
class. Modify the behavior of the append () method so that only objects
of str type can be added to the list. If you try to add a different type of
object raise TypeE rror with message:
'Only objects of type str can be added to the list.'
Then create an instance of the StringListOnly class and add the
following objects with the append() method:
'Data'
'Science'
In response, print result to the console.
Expected result:
['Data', 'Science']
Solution:
66. Create a class named StringListOnly that extends the built-in list
class. Modify the behavior of the append() method so that only objects
of str type an be added to the list. Replace all uppercase letters with
lowercase before adding the object to the list. If you try to add a
different type of object raise TypeE rror with message:
'Only objects of type str can be added to the list.'
Then create an instance of the StringListOnly class and add the
following objects with the append() method:
'Data'
• 'Science'
• 'Machine Learning'
In response, print result to the console.
Expected result:
['data', 'science', 'machine learning']
Solution:
67. An implementation of the Product class is given. Implement a class
named Warehouse which in the init ( ) method sets an
instance attribute of the Warehouse class named products to
an empty list.
Then create an instance of the Warehouse class named warehouse and
display the value of the products attribute to the console.
Expected result:
[]
import uuid
class Product:
def __repr__(self):
return f"Product(product_name='{self.product_name}', price=
{self.price})"
@staticmethod
def get_id():
return str(uuid.uuid4().fields[-1])[:6]
Solution:
68. The implementation of the classes: Product and Warehouse is given. To
the Warehouse class, add a method named add_product( ) that allows you to
add an instance of the Product class to the products list. If the product name
is already in the products list, skip adding the product.
Next, create an instance of the Warehouse class named warehouse. Using the
add_product() method add the following products:
'Laptop', 3900.0
'Mobile Phone', 1990.0
'Mobile Phone', 1990.0
Note that the second and third products are duplicates. The add_product()
method should avoid adding duplicates. Print the products attribute of the
warehouse instance to the console.
Expected result:
[Product(product_name='Laptop', price=3900.0),
Product(product_name='Mobile Phone', price=1990.0)]
import uuid
class Product:
def __repr__(self):
return f"Product(product_name='{self.product_name}', price=
{self.price})"
@staticmethod
def get_id():
return str(uuid.uuid4().fields[-1])[:6]
class Warehouse:
def __init__(self):
self.products = []
Solution:
import uuid
class Product:
@staticmethod
def get_id():
return str(uuid.uuid4().fields[-1])[:6]
class Warehouse:
def __init__(self):
self.products = []
warehouse = Warehouse()
warehouse.add_product('Laptop', 3900.0)
warehouse.add_product('Mobile Phone', 1990.0)
print(warehouse.products)
69. The implementation of the classes: Product and Warehouse is given. To
the Warehouse class, add a method named remove_product( ) that allows you
to remove an instance of the Product class from the products list with a given
product name. If the product name is not in the products list, just skip.
Next, create an instance of the Warehouse class named warehouse. Using the
add_product() method add the following products:
'Laptop', 3900.0
'Mobile Phone', 1990.0
• 'Camera', 2900.0
Then, using the remove_product() method, remove the product named
'Mobile Phone' . In response, print the products attribute of the warehouse
instance to the console.
Expected result:
[Product(product_name='Laptop', price=3900.0),
Product(product_name='Camera', price=2900.0)]
import uuid
class Product:
def __repr__(self):
return f"Product(product_name='{self.product_name}', price=
{self.price})"
@staticmethod
def get_id():
return str(uuid.uuid4().fields[-1])[:6]
class Warehouse:
def __init__(self):
self.products = []
class Product:
def __repr__(self):
return f"Product(product_name='{self.product_name}', price=
{self.price})"
@staticmethod
def get_id():
return str(uuid.uuid4().fields[-1])[:6]
class Warehouse:
def __init__(self):
self.products = []
import uuid
class Product:
def __repr__(self):
return f"Product(product_name='{self.product_name}', price=
{self.price})"
@staticmethod
def get_id():
return str(uuid.uuid4().fields[-1])[:6]
class Warehouse:
def __init__(self):
self.products = []
Solution:
import uuid
class Product:
def __init__(self, product_name, price):
self.product_id = self.get_id()
self.product_name = product_name
self.price = price
def __repr__(self):
return f"Product(product_name='{self.product_name}', price=
{self.price})"
def __str__(self):
return f'Product Name: {self.product_name} | Price: {self.price}'
@staticmethod
def get_id():
return str(uuid.uuid4().fields[-1])[:6]
class Warehouse:
def __init__(self):
self.products = []
71. The implementation of the classes: Product and Warehouse is given. Add
a method to the Warehouse class named dispiay_products() that displays all
products in the products attribute of the Warehouse class.
Then create an instance of the Warehouse class named warehouse and
execute the following code:
warehouse.add_product(1 Laptop', 3900.0)
warehouse.add_product('Mobile Phone', 1990.0)
warehouse.add_product('Cañera', 2900.0)
import uuid
class Product:
def __repr__(self):
return f"Product(product_name='{self.product_name}', price=
{self.price})"
def __str__(self):
return f'Product Name: {self.product_name} | Price: {self.price}'
@staticmethod
def get_id():
return str(uuid.uuid4().fields[-1])[:6]
class Warehouse:
def __init__(self):
self.products = []
def __repr__(self):
return f"Product(product_name='{self.product_name}', price=
{self.price})"
def __str__(self):
return f'Product Name: {self.product_name} | Price: {self.price}'
@staticmethod
def get_id():
return str(uuid.uuid4().fields[-1])[:6]
class Warehouse:
def __init__(self):
self.products = []
def display_products(self):
for product in self.products:
print(product)
warehouse = Warehouse()
warehouse.add_product('Laptop', 3900.0)
warehouse.add_product('Mobile Phone', 1990.0)
warehouse.add_product('Camera', 2900.0)
warehouse.display_products()
72. The implementation of the classes: Product and Warehouse is
given. Add a method called sort_by_price( ) to the Warehouse class
that returns an alphabetically sorted list of products. The sort_by_price(
) method also takes an argument ascending set to True by default,
which means an ascending sort. If False is passed, reverse the sort
order.
Then create an instance of the Warehouse class named warehouse and
execute the following code:
warehouse.add_product(1 Laptop', 3900.0)
warehouse.add_product('Mobile Phone', 1990.0)
warehouse.add_product('Cañera', 2900.0)
warehouse.add_product('USB Cable', 24.9)
warehouse.add_product('House', 49.0)
In response, use the sort_by_price( ) method to print a sorted list of
products to the console as shown below.
Expected result:
Product(product_name='USB Cable', price=24.9)
Product(product_name='Mouse', price=49.0)
Product(product_name='Mobile Phone', price=1990.0)
Product(product_name='Camera', price=2900.O)
Product(product_name='Laptop', price=3900.0)
import uuid
class Product:
def __repr__(self):
return f"Product(product_name='{self.product_name}',
price={self.price})"
@staticmethod
def get_id():
return str(uuid.uuid4().fields[-1])[:6]
class Warehouse:
def __init__(self):
self.products = []
def display_products(self):
for product in self.products:
print(f'Product ID: {product.product_id} | Product name: '
f'{product.product_name} | Price: {product.price}')
Solution:
import uuid
class Product:
def __repr__(self):
return f"Product(product_name='{self.product_name}', price=
{self.price})"
@staticmethod
def get_id():
return str(uuid.uuid4().fields[-1])[:6]
class Warehouse:
def __init__(self):
self.products = []
def display_products(self):
for product in self.products:
print(f'Product ID: {product.product_id} | Product name: '
f'{product.product_name} | Price: {product.price}')
warehouse = Warehouse()
warehouse.add_product('Laptop', 3900.0)
warehouse.add_product('Mobile Phone', 1990.0)
warehouse.add_product('Camera', 2900.0)
warehouse.add_product('USB Cable', 24.9)
warehouse.add_product('Mouse', 49.0)
for product in warehouse.sort_by_price():
print(product)
73. The implementation of the classes: Product and Warehouse
is given. Complete the implementation of the method named
search_product( ) of the Warehouse class that allows you to return a list
of products containing the specified name ( query argument).
Then create an instance of the Warehouse class named warehouse and
execute the following code:
warehouse.add_product(1 Laptop', 3900.0)
warehouse.add_product('Mobile Phone', 1990.0)
warehouse.add_product('Cañera', 2900.0)
warehouse.add_product(1 USB Cable', 24.9)
warehouse.add_product(1 Mouse1, 49.0)
In response, call search_product() method and find all products that
contain the letter 'm'.
Expected Result:
[Product(product_name='Mobile Phone', price=1990.0),
Product(product_name='Mouse', price=49.0)]
import uuid
class Product:
def __repr__(self):
return f"Product(product_name='{self.product_name}', price=
{self.price})"
@staticmethod
def get_id():
return str(uuid.uuid4().fields[-1])[:6]
class Warehouse:
def __init__(self):
self.products = []
def display_products(self):
for product in self.products:
print(f'Product ID: {product.product_id} | Product name: '
f'{product.product_name} | Price: {product.price}')
def __repr__(self):
return f"Product(product_name='{self.product_name}', price=
{self.price})"
@staticmethod
def get_id():
return str(uuid.uuid4().fields[-1])[:6]
class Warehouse:
def __init__(self):
self.products = []
def add_product(self, product_name, price):
product_names = [product.product_name for product in
self.products]
if not product_name in product_names:
self.products.append(Product(product_name, price))
def display_products(self):
for product in self.products:
print(f'Product ID: {product.product_id} | Product name: '
f'{product.product_name} | Price: {product.price}')
Edcredibly App –
https://play.google.com/store/apps/details?id=com.edcredibly.courses
Using the '==' operator to compare two instances of a class in Python results in 'false' even if they have identical attribute values because '==' checks for object identity rather than equality of the attributes. This means it checks if the two instances are stored at the same memory location, which they are not, even if their attribute values are the same . Each time a class instance is created, it is allocated a unique memory address, differentiating it from other instances even with the same attribute values .
In Python, access to class variables and methods is controlled by naming conventions that simulate direct access modifiers like private and protected. The public nature of attributes means they are generally open for access, but a single underscore prefix ('_') denotes a protected member, suggesting it should not be accessed from outside the class. A double underscore prefix ('__') makes an attribute private, mangling its name internally to prevent specific naming conflicts, simulating private access. Although Python relies on convention rather than enforcement for access control, these practices influence programmers to observe encapsulation principles .
In Python, memory is not allotted when a class is defined. A class definition only creates a blueprint for objects. Memory allocation occurs only during the creation of an instance of the class, which is when an object is instantiated. When an object is created, using the class name followed by parentheses, memory is allocated to that particular object. This distinction means that the class acts as a template, whereas the object is a concrete instance with specific memory allocated for storing its data .
Class attributes differ from instance attributes in scope and value application. Class attributes are shared among all instances of a class; they have the same value for every instance unless explicitly overridden. Instance attributes, on the other hand, are unique to each instance and can differ among instances. This means class attributes are used for constants or shared data, whereas instance attributes are used for data that vary per object. For example, in a Human class, 'species' could be a class attribute ('Homo Sapiens') applicable to all instances, while 'name' or 'age' are instance attributes unique to each person .
Inheritance in object-oriented programming allows a class to inherit attributes and methods from another class, known as the parent class. This mechanism supports code reuse by allowing child classes to use and extend the properties of their parent classes without having to rewrite code. A real-world analogy can be seen in family genetics, where certain physical traits and capabilities are passed from parents to children. In programming, just as children inherit their parents’ features, a class can inherit methods and attributes from a parent class, facilitating efficient code reuse and organization .
Encapsulation contributes to data security in Python by restricting unauthorized access to an object's attributes and methods. By encapsulating data, Python classes can prevent external entities from directly interacting with or modifying class members. This is achieved through access modifiers, which control the visibility of attributes and methods. For instance, by prefixing attributes with an underscore or double underscore, they can be made accessible only within the class itself or its subclasses, thus hiding them from external access. Encapsulation therefore enhances security by allowing controlled access through getter and setter methods while maintaining internal integrity .
The `__init__` method in Python is a special method used to initialize a new instance of a class. It sets the initial state of the object by assigning values to the object's attributes based on the parameters provided during object creation. This method ensures each instance of a class can have different attribute values, and while any number of parameters can be passed to it, `self` is always the first parameter . The `self` keyword in Python is a reference to the current instance of the class. It is used within class methods to access instance attributes and other methods. When defining an instance method, `self` is the first parameter, allowing you to manipulate instance data from within the method .
Two instances of the same class in Python cannot have identical memory addresses if they are separate objects. Each time a new instance is created, Python allocates a distinct memory location for it. Thus, comparing two instances created from the same class using the `==` operator results in `False`, as both will have different memory allocations . Memory allocation in Python occurs during the creation of an object or instance, not during the class definition . The `self` parameter in the initialization method `__init__()` pertains to each unique instance, further indicating that each instance has its unique memory address ."}
Getter and setter methods are used in Python to achieve encapsulation, a core concept of object-oriented programming. Encapsulation is the practice of restricting direct access to some of an object's components and can be used to hide both the data (like variables) and the implementation details of methods from outside interference and misuse. Getters and setters are methods used to access and update private or protected variables that cannot be accessed directly. A getter method retrieves the value of a private variable, while a setter method allows for setting or updating the value of that variable. This ensures that any change to the data is controlled and any internal logic for maintaining data integrity is applied. In this way, getters and setters help enforce data hiding by controlling how variables are accessed and modified . For example, in a class representing a book, the getBookName() method might serve as a getter to access the book name, while setBookName() might act as a setter to change it. Users of the class must use these methods to access or modify data, rather than accessing the data directly, thus promoting encapsulation ."}
Polymorphism in Python allows functions or operators to have different behaviors based on the objects they are handling. For example, the `len()` function is polymorphic; it can calculate the length of a list, tuple, dictionary, or string, returning an appropriate value for each data type . Additionally, polymorphism allows methods in different classes to have the same name but different implementations. This means a method in a parent class can be overridden in a subclass to provide specific behavior (method overriding). For instance, a class `Animal` might have a method `speak()`, and two subclasses `Dog` and `Cat` could override this to return "Bark" and "Meow" respectively, thus demonstrating polymorphism .