Course
Introduction
In the last chapter we learnt the basics of programming, you were shown how to store data in data structures such as lists, strings, integers, dictionaries, and others. And you were shown how to create behavior for your program using keywords, and later using functions to group these keywords. This coding approache is called Logic Programming.
However, there are different approaches or perspectives in computer programming which we call programming paradigms. They provide various ways of organizing and structuring code to solve a particular problem.
Each paradigm has its own strengths, weaknesses, and suitability for different types of problems and use cases. Some programming languages may support multiple paradigms, while others may have limited support for one specific paradigm.
In this course we will get to know the object-oriented programming (OOP), a programming paradigm widely used in Python.
PS: At this stage of the course, we assume that you know the basics of Python.
Object-oriented programming (OOP)
What is it ?
Object-oriented programming (OOP) is an approach that organizes software design based on objects, which are data fields with unique attributes and behaviors, instead of functions and logic.
Why we use it ?
One of the main benefits of OOP is its organization, which makes it easier for developers to collaborate on a project by dividing it into smaller groups. Additionally, OOP offers several other advantages, such as code reusability, scalability, and efficiency.
OOP Basic Concepts
-
Class: A class is a blueprint for creating objects. It defines a set of attributes (properties) and methods (functions) that the objects created from the class will have. For example, you could create a "Person" class with attributes like name, age, and address, and methods like "introduce" and "greet".
-
Object: An object is an instance of a class. When you create an object from a class, you get a specific "realization" of the class, with its own set of attributes and methods. For example, you could create two "Person" objects, "John" and "Jane", each with their own name, age, and address.
-
Attributes: Attributes are the properties or characteristics of an object. They define the state of the object. In the example of the "Person" class, the attributes would be name, age, and address.
-
Methods: Methods are the actions or behaviors of an object. They define what the object can do. In the example of the "Person" class, the methods would be "introduce" and "greet".
Here is a simple example of a Python class that defines a "Person" object:
class Person:
def __init__(self, name, age, address):
self.name = name
self.age = age
self.address = address
def introduce(self):
return f"Hi, my name is {self.name} and I am {self.age} years old."
def greet(self, other_person):
return f"Hello {other_person.name}, it's nice to meet you!"
john = Person("John", 30, "123 Main St.")
jane = Person("Jane", 25, "456 Elm St.")
print(john.introduce()) # Output: Hi, my name is John and I am 30 years old.
print(jane.greet(john)) # Output: Hello John, it's nice to meet you!
When to use it ?
-
Modeling real-world objects: You can create classes to model real-world objects in Python, such as dogs, cars, or books. For example, you can create a "Dog" class with properties like breed, name, and age, and methods like "bark", "eat", and "sleep". This makes it easier to manipulate and work with instances of the class, and to keep track of the state of each object.
-
Building games: OOP is often used in game development to model game objects and their behaviors. For example, you can create a "Player" class to represent a player in a game, with properties like position, health, and score, and methods like "move", "attack", and "jump".
-
Database applications: You can use OOP to interact with databases in Python. For example, you can create a "Record" class to represent a record in a database table, with properties like id, name, and date, and methods like "insert", "update", and "delete".
-
Web development: OOP is commonly used in web development to build applications and services. For example, you can create a "User" class to represent a user of your application, with properties like name, email, and password, and methods like "register", "login", and "logout".
-
Scientific simulations: OOP can be used to create scientific simulations, such as physical simulations or financial models. For example, you can create a "Particle" class to represent a particle in a physical simulation, with properties like position, velocity, and mass, and methods like "move", "collide", and "absorb".
These are just a few examples of how OOP can be used in Python. With its powerful and flexible object-oriented features, OOP is a widely used paradigm in Python and can be applied to many different types of projects.
Some examples
- Car: Create a class Car that represents a car. The class should have properties brand, model, and year, and a method drive that makes the car drive (print "Driving the car !").
## Class implementation
class Car:
def __init__(self, brand, model, year):
self.brand = brand
self.model = model
self.year = year
def drive(self):
print("Driving the car !")
## Object declaration
car = Car("Toyota", "Camry", 2020)
print(car.drive())
# Output: Driving the car !
- Dog: Create a class Dog that represents a dog. The class should have properties name, breed, and age, and a method bark that makes the dog bark (print "Woof!").
## Class implementation
class Dog:
def __init__(self, name, breed, age):
self.name = name
self.breed = breed
self.age = age
def bark(self):
print("Woof!")
## Object declaration
dog = Dog("Max", "Labrador", 5)
print(dog.bark())
# Output: Woof!
Let's code !
Operator overloading
Operator overloading allows objects of user-defined classes to behave like built-in data types. This means that you can use familiar syntax for objects of your classes, making your code more intuitive and easier to read.
For example, consider a class for a 2D point:
class Point2D:
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return f"({self.x}, {self.y})"
class Point2D:
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return f"({self.x}, {self.y})"
def __add__(self, other):
return Point2D(self.x + other.x, self.y + other.y)
In this example, the __add__ method takes another Point2D object as its argument and returns a new Point2D object that represents the sum of the two points. This allows you to use the + operator with instances of your class, just like you would with built-in data types.
You can also overload other operators, such as -, *, /, <, >, and so on, by defining the corresponding special methods, such as __sub__, __mul__, __truediv__, __lt__, __gt__, and so on.
Here's an example that overloads the subtraction operator:
class Point2D:
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return f"({self.x}, {self.y})"
def __add__(self, other):
return Point2D(self.x + other.x, self.y + other.y)
def __sub__(self, other):
return Point2D(self.x - other.x, self.y - other.y)
Cheat sheet for Class Special Methods:
Operator | Method |
---|---|
String representation | __str__ |
Addition (+) | __add__ |
Subtraction (-) | __sub__ |
Multiplication (*) | __mul__ |
Power (**) | __pow__ |
Division (/) | __truediv__ |
Floor Division (//) | __floordiv__ |
Remainder (modulo)(%) | __mod__ |
Lesser than (<) | __lt__ |
Greater than (>) | __gt__ |
Lesser than or equal (<=) | __le__ |
Greater than or equal (>=) | __ge__ |
Equal (==) | __eq__ |
Not equal (!=) | __ne__ |
Absolute value (abs()) | __abs__ |
Bitwise AND(&) | __and__ |
Bitwise OR (|) | __or__ |
Bitwise NOT(~) | __invert__ |
Inheritance in Object-Oriented Programming
What is it ?
Inheritance is a mechanism in Object-Oriented Programming (OOP) that allows a new class to be defined based on an existing class. The new class, known as the subclass, inherits attributes and behavior from the existing class, known as the superclass. This enables code reuse, allowing new classes to be defined with little or no modifications to the existing classes.
For example, consider a superclass called Animal which has attributes such as name, species, and age, and a method called make_sound() that returns the sound the animal makes. We can create a subclass of Animal called Dog which inherits all of the attributes and behavior of the Animal class. We can also add additional attributes specific to dogs such as breed and override the make_sound() method to return the specific sound a dog makes, like "bark".
class Animal:
def __init__(self, name, species, age):
self.name = name
self.species = species
self.age = age
def make_sound(self):
return "Sound made by the animal"
class Dog(Animal):
def __init__(self, name, breed, age):
Animal.__init__(self, name, "Dog", age)
self.breed = breed
def make_sound(self):
return "Bark"
dog = Dog("Rufus", "Labrador", 5)
print(dog.name) # Rufus
print(dog.species) # Dog
print(dog.age) # 5
print(dog.breed) # Labrador
print(dog.make_sound()) # Bark
In this example, the Dog class inherits the attributes name, species, and age from the Animal class and also adds an additional attribute breed. The method make_sound() is also overridden in the Dog class to return a specific sound for dogs.
Inheritance provides a way to model relationships between classes, and is an important concept in OOP for code reuse and organization. In Python, inheritance is an is-a relationship. That is, we use inheritance only if there exists an is-a relationship between two classes. For example,
- Car is a Vehicle
- Student is a Person
- Cat is an Animal
Here, Car can inherit from Vehicle, Apple can Student from Person, and so on.
Polymorphism and Abstraction
-
Polymorphism : Is the ability of an object to take on multiple forms. It allows objects of different classes to be treated as objects of the same class. This means that you can write a single function or method that can work with objects of different classes, as long as they implement the same interface.
-
Abstraction : Is a technique that allows you to simplify complex systems by ignoring irrelevant details and focusing on the essential features of an object. It is achieved by defining an interface that exposes the essential features of an object, while hiding the implementation details.
Here's an example in Python to demonstrate the difference between polymorphism and abstraction:
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 * self.radius
def print_area(shape):
print(shape.area())
rect = Rectangle(10, 20)
circ = Circle(5)
print_area(rect) # 200
print_area(circ) # 78.5
In this example, the Shape class serves as an abstract class and defines an abstract method area. The Rectangle and Circle classes inherit from Shape and provide their own implementation of the area method.
This demonstrates polymorphism, as objects of different classes (Rectangle and Circle) can be treated as objects of the same class (Shape). The print_area function demonstrates polymorphism, as it can accept objects of different classes (Rectangle and Circle) as long as they implement the same interface (area method).
At the same time, the Shape class demonstrates abstraction by defining an interface that exposes the essential features of a shape, while hiding the implementation details. The Rectangle and Circle classes implement the area method, but the details of the implementation are hidden from the user. The user only sees the essential features of the object (the area method).
Multiple and Multilevel Inheritance
-
Multiple Inheritance: is a feature of Object Oriented Programming (OOP) languages where a class can inherit properties and attributes from more than one parent class. This means that a single class can have multiple base classes and it can inherit properties and attributes from all of them.
For example, consider a scenario where you have two classes: Shape and Color. The class Shape defines the properties of a 2-D shape such as its area, perimeter, etc. The class Color defines the color of an object. Now, you want to create a new class Rectangle which is a shape and has a color. You can achieve this by using multiple inheritance.
Here's an example implementation in Python:
class Shape:
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
def perimeter(self):
return 2 * (self.width + self.height)
class Color:
def __init__(self, color):
self.color = color
class Rectangle(Shape, Color):
pass
rect = Rectangle(10, 20, 'red')
print(rect.area())
print(rect.perimeter())
print(rect.color)
In this example, the class Rectangle inherits from both Shape and Color classes. This means that it has all the attributes and methods defined in both the classes.
-
Multilevel Inheritance : is a type of inheritance where a class inherits properties and attributes from its parent class, and the parent class inherits from its parent class, and so on.
For example, consider a scenario where you have a class Animal which defines basic properties of an animal such as its name, age, and breed. Another class Mammal inherits from Animal class and adds new properties such as type of fur, etc. Finally, a new class Cat is created which inherits from Mammal class and adds new properties specific to cats such as the type of meow, etc.
Here's an example implementation in Python:
class Animal:
def __init__(self, name, age, breed):
self.name = name
self.age = age
self.breed = breed
class Mammal(Animal):
def __init__(self, name, age, breed, fur_type):
Animal.__init__(self, name, age, breed)
self.fur_type = fur_type
class Cat(Mammal):
def __init__(self, name, age, breed, fur_type, meow_type):
Mammal.__init__(self, name, age, breed, fur_type)
self.meow_type = meow_type
cat = Cat('Tom', 3, 'Siamese', 'short hair', 'loud')
print(cat.name)
print(cat.age)
print(cat.breed)
print(cat.fur_type)
print(cat.meow_type)
In this example, the class Cat inherits from the class Mammal which in turn inherits from the class Animal. This creates a hierarchy of classes where each class inherits properties and attributes from its parent class.