Object-Oriented Programming (OOP)
Object-Oriented Programming (OOP)
Programming (OOP)
Reading Material
Topics covered in this Chapter:
1. Introduction to Object-Oriented Programming (OOP)
- Advantages of OOP
- Defining Classes
- Creating Objects
3. Inheritance
- Types of Inheritance
- Method Overriding
- Super() Function
- Multiple Inheritance
4. Polymorphism
- Method Overloading
- Operator Overloading
- Duck Typing
5. Encapsulation
- Access Modifiers
- Property Decorators
6. Abstraction
- Abstract Classes
- Interfaces
Objects: These are like smart Lego blocks. Each object contains both information (data) and actions it can
perform (methods).
PW Skills
2. Classes: Think of these as blueprints for creating objects. Just like you might have a blueprint for a car before
you build it, a class is a plan for making objects.
3. Encapsulation: This is like keeping your toys in a toy box. It means wrapping up data and the methods that
work with that data into a single unit (the object).
4. Inheritance: Imagine if you could create a new type of Lego block that has all the features of an existing
block, plus some new ones. That's what inheritance does in OOP.
5. Polymorphism: This fancy word means that different objects can respond to the same message in different
ways. It's like how both a dog and a cat can "speak," but they make different sounds.
Advantages of OOP:
2. You can reuse code more easily, saving time and effort.
Procedural programming is like following a recipe step by step. OOP, on the other hand, is more like setting up a
kitchen where each appliance knows how to do its job. Here's a quick comparison:
Procedural:
OOP:
In the next section, we'll dive deeper into classes and objects, which are the building blocks of OOP.
PW Skills
Defining Classes:
A class is like a blueprint for creating objects. It defines what properties and abilities an object will have.
class GameCharacter:
self.name = name
self.health = health
self.power = power
def attack(self):
self.health -= damage
In this example
We define a class called `GameCharacter`
The `__init__` method is a special method called when we create a new character. It sets up the initial
values for the character
We have two other methods: `attack` and `take_damage`.
Creating Objects:
An object is an instance of a class. It's like a real character created from our blueprint.
```python
```
Here, we've created two objects (characters) from our `GameCharacter` class.
Instance variables are properties that belong to each individual object. In our example, `name`, `health`, and
`power` are instance variables
Instance methods are functions that belong to the class and can be called on individual objects. `attack` and
`take_damage` are instance methods.
```python
```
PW Skills
Class Variables and Methods:
Sometimes, we want variables or methods that are shared by all instances of a class.
```python
class GameCharacter:
self.name = name
self.health = health
self.power = power
GameCharacter.total_characters += 1
@classmethod
def show_total_characters(cls):
```
The constructor (`__init__` method) is called when an object is created. We've already seen this in action
The destructor (`__del__` method) is called when an object is about to be destroyed. It's less commonly
used
```python
class GameCharacter:
self.name = name
def __del__(self):
# Using it
```
PW Skills
These concepts form the foundation of working with classes and objects in Python. They allow you to create
structured, reusable code that models real-world entities or concepts in your programs. In the next section, we'll
explore how we can build upon these ideas with inheritance.
3. Inheritance
Inheritance is like passing down traits from parents to children. In programming, it allows us to create new
classes based on existing ones, inheriting their attributes and methods.
Types of Inheritance:
1. Single Inheritance:
This is when a class inherits from one parent class. It's the simplest form of inheritance.
Example:
```python
class Animal:
self.name = name
def speak(self):
pass
class Dog(Animal):
PW Skills
def speak(self):
fido = Dog("Fido")
```
Here, `Dog` inherits from `Animal`. It gets the `name` attribute from `Animal` and overrides the `speak` method.
2. Multiple Inheritance:
This is when a class inherits from more than one parent class.
Example:
```python
class Flying:
def fly(self):
class Swimming:
def swim(self):
pass
donald = Duck()
```
Here, `Duck` inherits from both `Flying` and `Swimming`, gaining abilities from both.
3. Multilevel Inheritance:
Example:
```python
class Grandparent:
def speak(self):
class Parent(Grandparent):
def talk(self):
class Child(Parent):
def babble(self):
baby = Child()
```
PW Skills
Here, `Child` inherits from `Parent`, which inherits from `Grandparent`.
Method Overriding:
This happens when a child class provides a specific implementation for a method that is already defined in its
parent class.
Example:
```python
class Animal:
def make_sound(self):
class Cat(Animal):
def make_sound(self):
return "Meow!"
generic_animal = Animal()
kitty = Cat()
Super() Function:
The `super()` function is used to call methods from the parent class. It's especially useful when you want to
extend the functionality of a parent method rather than completely replacing it.
Example:
```python
class Person:
self.name = name
self.age = age
class Student(Person):
self.grade = grade
```
Here, `Student` uses `super()` to call the `__init__` method of `Person`, then adds its own initialization for `grade`.
When using multiple inheritance, Python needs to decide which method to call if the same method name exists
in multiple parent classes. It uses the Method Resolution Order (MRO) to make this decision.
PW Skills
Example:
```python
class A:
def greet(self):
class B(A):
def greet(self):
class C(A):
def greet(self):
pass
d = D()
```
In this case, even though `D` inherits from both `B` and `C`, it uses the `greet` method from `B` because `B` comes
first in the inheritance list.
Inheritance is a powerful feature that promotes code reuse and allows for the creation of flexible and modular
code structures. It's a fundamental concept in OOP that helps in building complex systems by extending and
specializing existing code.
4. Polymorphism
Polymorphism is a fancy word that simply means "many forms." In programming, it allows objects of different
types to be treated as objects of a common base type. This concept is crucial for writing flexible and reusable
code.
1. Method Overloading:
While Python doesn't support traditional method overloading like some other languages, we can simulate it
using default arguments or variable-length arguments.
```python
class Calculator:
return a + b + c
calc = Calculator()
print(calc.add(5)) # Output: 5
```
PW Skills
In this example, the `add` method can handle different numbers of arguments.
2. Operator Overloading:
This allows us to define how operators work for our custom objects.
Example:
```python
class Point:
self.x = x
self.y = y
def __str__(self):
p1 = Point(1, 2)
p2 = Point(3, 4)
p3 = p1 + p2
``
Here, we've defined how the `+` operator should work with our `Point` objects.
3. Duck Typing:
This is a concept in Python where the type or class of an object is less important than the methods it defines. "If
it walks like a duck and quacks like a duck, it's a duck."
Example:
```python
class Dog:
def speak(self):
return "Woof!"
class Cat:
def speak(self):
return "Meow!"
class Human:
def speak(self):
return "Hello!"
def make_speak(animal):
print(animal.speak())
dog = Dog()
cat = Cat()
human = Human()
```
PW Skills
In this example, `make_speak` doesn't care about the type of `animal`. It only cares that `animal` has a `speak`
method.
This is when a subclass provides a specific implementation for a method that is already defined in its
superclass.
Example:
```python
class Shape:
def area(self):
return 0
class Square(Shape):
self.side = side
def area(self):
return self.side ** 2
class Circle(Shape):
self.radius = radius
def area(self):
print(f"Area: {shape.area()}")
# Output:
# Area: 25
# Area: 28.26
```
Here, `Square` and `Circle` both override the `area` method of `Shape`. When we call `area()` on each shape, the
appropriate method is called based on the actual type of the object.
Note: Static polymorphism (static binding) is a kind of polymorphism that occurs at compile time. An example
of compile-time polymorphism is method overloading.
Polymorphism is a powerful concept that allows for more flexible and extensible code. It enables us to write
code that can work with objects of multiple types, as long as they support the operations we're using. This leads
to more modular and reusable code, as we can write functions that operate on abstractions rather than
specific implementations.
In the next section, we'll explore encapsulation, another fundamental principle of OOP that helps in organizing
and protecting our data.
PW Skills
5. Encapsulation
Encapsulation is like wrapping up your data and methods in a neat package. It's about bundling the data
(attributes) and the methods that work on that data within a single unit (class). This concept helps in hiding the
internal details of how an object works and protects the data from unauthorized access.
1. Access Modifiers:
In Python, we use naming conventions to indicate the access level of attributes and methods
Example:
```python
class Employee:
def display_info(self):
def __calculate_bonus(self):
```
These are methods used to get and set the values of private attributes. They allow us to add validation or
computation when accessing or modifying data.
Example:
```python
class BankAccount:
self.__balance = balance
def get_balance(self):
return self.__balance
if balance >= 0:
self.__balance = balance
else:
account = BankAccount(1000)
account.set_balance(1500)
PW Skills
3. Property Decorators:
Python provides a more elegant way to implement getters and setters using the `@property` decorator.
Example:
```python
class Circle:
self.__radius = radius
@property
def radius(self):
return self.__radius
@radius.setter
if value > 0:
self.__radius = value
else:
@property
def area(self):
circle = Circle(5)
print(circle.radius) # Output: 5
circle.radius = 7
print(circle.radius) # Output: 7
In this example
`radius` is a property that allows getting and setting the private `__radius` attribute
`area` is a read-only property that calculates the area based on the radius.
Benefits of Encapsulation:
1. Data Protection: It prevents accidental modification of data from outside the class.
2. Flexibility: We can change the internal implementation without affecting the code that uses the class.
3. Data Validation: We can add checks when setting values to ensure data integrity.
4. Abstraction: It hides the complex implementation details, showing only what's necessary.
Encapsulation is crucial for creating robust and maintainable code. It allows us to control how data is accessed
and modified, preventing unintended side effects and making our code more modular and easier to
understand.
In the next section, we'll explore abstraction, which is closely related to encapsulation but focuses more on
hiding complexity and providing a simpler interface to work with objects.
PW Skills
6. Abstraction
Abstraction is about simplifying complex systems by modeling classes based on the essential properties and
behaviors they need to have, while hiding the unnecessary details. It's like using a TV remote - you don't need to
know how it works internally, you just need to know which buttons to press.
1. Abstract Classes:
An abstract class is a class that is meant to be inherited from, but not instantiated directly. It often contains one
or more abstract methods - methods that are declared but don't have an implementation.
In Python, we use the `abc` module (Abstract Base Classes) to create abstract classes.
Example:
```python
class Shape(ABC):
@abstractmethod
def area(self):
pass
@abstractmethod
def perimeter(self):
pass
class Rectangle(Shape):
self.length = length
self.width = width
def area(self):
def perimeter(self):
rect = Rectangle(5, 3)
```
In this example
`Shape` is an abstract class with two abstract methods
We can't create an instance of `Shape` directly
`Rectangle` inherits from `Shape` and must implement all its abstract methods.
2. Interfaces:
Python doesn't have a formal interface keyword, but we can use abstract classes with only abstract methods to
create interface-like structures.
PW Skills
Example:
```python
class Drawable(ABC):
@abstractmethod
def draw(self):
pass
class Circle(Drawable):
def draw(self):
class Square(Drawable):
def draw(self):
def render(item):
print(item.draw())
circle = Circle()
square = Square()
Here, `Drawable` acts like an interface, defining a contract that classes must follow.
Python's `abc` module provides infrastructure for defining abstract base classes.
Example:
```python
class Animal(ABC):
@abstractmethod
def make_sound(self):
pass
@abstractmethod
def move(self):
pass
def breathe(self):
class Dog(Animal):
def make_sound(self):
return "Woof!"
def move(self):
dog = Dog()
```
PW Skills
In this example
`Animal` is an abstract base class with two abstract methods and one concrete method
`Dog` must implement all abstract methods from `Animal`
The `breathe` method is inherited as-is.
Benefits of Abstraction:
2. Code Reusability: Abstract classes can be used as a base for multiple concrete classes.
3. Flexibility: You can change the implementation of derived classes without affecting the abstract class.
4. Security: It helps in hiding certain details and only showing the important details of an object.
Abstraction is a powerful concept that allows you to create more organized and manageable code. It helps in
dealing with the complexity of large systems by breaking them down into more manageable pieces. By
focusing on what an object does rather than how it does it, abstraction supports better code organization and
easier maintenance.
This concludes our overview of the main concepts of Object-Oriented Programming. These principles -
Encapsulation, Inheritance, Polymorphism, and Abstraction - form the foundation of OOP and are crucial for
writing clean, efficient, and maintainable code.
PW Skills