0% found this document useful (0 votes)
3 views

Python Chapter 5 Notes by Ur Engineering Friend

The document provides an overview of Object-Oriented Programming (OOP) concepts in Python, including class and object creation, method overloading and overriding, data hiding, data abstraction, inheritance, and composition. It illustrates these concepts with examples, demonstrating how to define classes, create objects, and implement various OOP principles. The document emphasizes the importance of encapsulation, modularity, and code reuse in software development.

Uploaded by

pranavsp2810
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views

Python Chapter 5 Notes by Ur Engineering Friend

The document provides an overview of Object-Oriented Programming (OOP) concepts in Python, including class and object creation, method overloading and overriding, data hiding, data abstraction, inheritance, and composition. It illustrates these concepts with examples, demonstrating how to define classes, create objects, and implement various OOP principles. The document emphasizes the importance of encapsulation, modularity, and code reuse in software development.

Uploaded by

pranavsp2810
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 13

Programming with Python

Chapter 5th – Object Oriented Programming

Unit 5 Notes: UR Engineering Friend

Creating Class and Object

In Python, classes are created using the class keyword followed by the name of the class.
Within the class definition, you can define attributes and methods for the class.

Here is an example:

class Car:

# This is the class constructor

def __init__(self, make, model, year):

self.make = make

self.model = model

self.year = year

# This is a class method

def get_info(self):

return f"{self.make} {self.model} ({self.year})"

In this example, we have defined a Car class with three attributes (make, model, and year)
and one method (get_info). The __init__ method is a special method that is called when an
object of the class is created. It initializes the attributes of the class.
To create an object of the Car class, we can simply call the class with the required
arguments:

my_car = Car("Toyota", "Camry", 2020)

Now, my_car is an object of the Car class, and we can call its methods and access its
attributes:

print(my_car.get_info()) # Output: "Toyota Camry (2020)"

print(my_car.year) # Output: 2020

We can also create multiple objects of the Car class:

my_other_car = Car("Honda", "Civic", 2022)

print(my_other_car.get_info()) # Output: "Honda Civic (2022)"

Method Overloading

➢ Method overloading is not supported in Python in the same way as in other


programming languages like Java or C++. In those languages, method overloading
allows you to define multiple methods with the same name but different parameters.
➢ In Python, you can achieve similar functionality using default arguments or variable-
length arguments.

Here are two common ways to simulate method overloading in Python:

Using default arguments:

class Calculator:

def add(self, a, b=None, c=None):

if b is None and c is None:

return a

elif c is None:
return a + b

else:

return a + b + c

In this example, the add method can take one, two, or three arguments. If only one argument
is provided, it is returned as is. If two arguments are provided, they are added and the result is
returned. If three arguments are provided, they are all added and the result is returned.

Using variable-length arguments:

class Calculator:

def add(self, *args):

total = 0

for num in args:

total += num

return total

➢ In this example, the add method takes any number of arguments and adds them
together. You can call the method with one argument, two arguments, or any number
of arguments.
➢ Note that while these techniques can simulate method overloading, they don't provide
the same level of type safety and error checking as true method overloading in other
languages. It is important to write clear and well-documented code when using these
techniques to avoid confusion and errors.
Method Overloading

Method overriding is a concept in object-oriented programming that allows a subclass to


provide a different implementation for a method that is already defined in its parent class. In
Python, method overriding is achieved by defining a method with the same name in the
subclass as the one in the parent class.

Here is an example of method overriding in Python:

class Animal:

def make_sound(self):

print("Generic animal sound")

class Cat(Animal):

def make_sound(self):

print("Meow")

class Dog(Animal):

def make_sound(self):

print("Woof")

my_cat = Cat()

my_cat.make_sound() # Output: "Meow"

my_dog = Dog()

my_dog.make_sound() # Output: "Woof"

In this example, we have a base class Animal with a method make_sound. The Cat and Dog
classes inherit from the Animal class and override the make sound method with their own
implementations.
When we create an instance of Cat or Dog and call the make sound method, the
implementation from the subclass is used instead of the one from the parent class.

Data hiding

In Python, data hiding is a technique used to restrict the access to certain class attributes and
methods from outside the class. This is achieved by prefixing the attribute or method name
with two underscores (__).

Here is an example of data hiding in Python:

class Person:

def __init__(self, name, age):

self.name = name

self.__age = age

def get_age(self):

return self.__age

def set_age(self, age):

self.__age = age

my_person = Person("John", 30)

print(my_person.name) # Output: "John"

print(my_person.get_age()) # Output: 30

my_person.set_age(35)

print(my_person.get_age()) # Output: 35

# Trying to access the hidden attribute directly

print(my_person.__age) # Raises an AttributeError


➢ In this example, the Person class has a private attribute __age. This attribute can only
be accessed from within the class, using the get_age and set_age methods. If you try
to access the attribute directly from outside the class, you will get an AttributeError.
➢ Data hiding in Python is not as strict as in some other programming languages, like
Java, where private attributes and methods cannot be accessed from outside the class
at all. In Python, private attributes and methods can still be accessed if you know their
name and use the correct syntax. However, data hiding can still be useful for
encapsulating implementation details and making the code easier to maintain.

Data Abstraction

Data abstraction is a concept in object-oriented programming that refers to the separation of


the interface from the implementation details. It allows you to focus on the essential features
of an object and ignore the details that are not relevant to the task at hand.

In Python, data abstraction can be achieved using abstract classes and abstract methods. An
abstract class is a class that cannot be instantiated and has one or more abstract methods. An
abstract method is a method that does not have an implementation in the abstract class, but
must be implemented in any concrete subclass.

Here is an example of data abstraction in Python:

from abc import ABC, abstractmethod

class Shape(ABC):

@abstractmethod

def area(self):

pass

class Rectangle(Shape):

def __init__(self, width, height):


self.width = width

self.height = height

def area(self):

return self.width * self.height

class Circle(Shape):

def __init__(self, radius):

self.radius = radius

def area(self):

return 3.14 * self.radius ** 2

my_rectangle = Rectangle(3, 4)

print(my_rectangle.area()) # Output: 12

my_circle = Circle(5)

print(my_circle.area()) # Output: 78.5

# Trying to instantiate the abstract class

my_shape = Shape() # Raises a TypeError

➢ In this example, we have an abstract class Shape with one abstract method area. This
method is implemented differently in the concrete subclasses Rectangle and Circle.
When we create instances of these subclasses and call the area method, we get the
area of the corresponding shape.
➢ Note that we cannot instantiate the abstract class Shape directly, because it has one or
more abstract methods that do not have an implementation. We must create a concrete
subclass that implements all the abstract methods before we can create an instance of
the class.
➢ Data abstraction can help you write more modular and maintainable code, by
separating the essential features of an object from the implementation details. It can
also help you enforce certain design patterns and prevent common errors, like
forgetting to implement a method in a subclass.
Inheritance

➢ Inheritance is a fundamental concept in object-oriented programming that allows you


to define a new class based on an existing class. The new class is called the subclass,
and the existing class is called the superclass. The subclass inherits all the attributes
and methods of the superclass, and can also add its own attributes and methods, or
override the ones inherited from the superclass.
➢ In Python, inheritance is achieved by creating a new class that inherits from an
existing class.
➢ Here is an example:

class Animal:

def __init__(self, name, species):

self.name = name

self.species = species

def make_sound(self):

print("Generic animal sound")

class Cat(Animal):

def __init__(self, name, breed):

super().__init__(name, species="cat")

self.breed = breed

def make_sound(self):

print("Meow")

my_cat = Cat("Fluffy", "Persian")

print(my_cat.name) # Output: "Fluffy"


print(my_cat.species) # Output: "cat"

print(my_cat.breed) # Output: "Persian"

my_cat.make_sound() # Output: "Meow"

➢ In this example, we have a superclass Animal with an attribute name, an attribute


species, and a method make_sound. The subclass Cat inherits from the Animal class
and adds an attribute breed and overrides the make_sound method.
➢ When we create an instance of Cat and access its attributes and methods, we can see
that it has inherited the name and species attributes from the Animal class, and has
added its own breed attribute. We can also see that the make_sound method from the
Cat class is used instead of the one from the Animal class when we call
my_cat.make_sound().
➢ Inheritance can help you write more modular and reusable code by creating
hierarchies of related classes that share common attributes and methods. It can also
help you avoid code duplication by allowing you to define a common behavior in the
superclass and override it in the subclasses if necessary.

Composition Class

Composition is another fundamental concept in object-oriented programming that allows you


to create complex objects by combining simpler objects. It is a form of "has-a" relationship,
where an object of one class has one or more objects of another class as attributes.

In Python, composition is achieved by creating a new class that contains instances of other
classes as attributes.

Here is an example:

class Engine:

def start(self):
print("Engine started")

class Car:

def __init__(self):

self.engine = Engine()

def start(self):

self.engine.start()

print("Car started")

my_car = Car()

my_car.start() # Output: "Engine started" followed by "Car started"

➢ In this example, we have a class Engine that represents an engine, and a class Car that
represents a car. The Car class has an instance of the Engine class as an attribute.
When we create an instance of Car and call its start method, it calls the start method
of the Engine object first, and then prints "Car started".
➢ Composition can help you create complex objects by breaking them down into
simpler objects. It can also help you reuse existing code by creating objects that
contain other objects with useful functionality. Additionally, it can help you avoid the
pitfalls of inheritance, such as tight coupling and the fragile base class problem.

Customization via inheritance Specializing

➢ Inheritance and specialization allow you to customize the behaviour of a class by


creating a subclass that overrides or extends its methods. This is known as
polymorphism, which means that the same method can be used with objects of
different classes, if they have a common interface.
➢ Here is an example of how you can use inheritance and specialization to create a
specialized method in Python:

class Shape:

def area(self):

pass

class Rectangle(Shape):

def __init__(self, width, height):

self.width = width

self.height = height

def area(self):

return self.width * self.height

class Circle(Shape):

def __init__(self, radius):

self.radius = radius

def area(self):

return 3.14 * self.radius ** 2

my_rectangle = Rectangle(10, 5)

my_circle = Circle(7)

print(my_rectangle.area()) # Output: 50

print(my_circle.area()) # Output: 153.86

➢ In this example, we have a superclass Shape with a method area that returns the area
of a shape. The subclass Rectangle overrides the area method to calculate the area of a
rectangle, and the subclass Circle overrides the area method to calculate the area of a
circle.
➢ When we create instances of Rectangle and Circle and call their area methods, we can
see that they behave differently, based on their specialized implementation of the area
method.
➢ This approach allows you to reuse the code of the superclass and customize it in the
subclasses. You can also create other subclasses of Shape and override its methods to
create other specialized behaviours.

You might also like