Classes and Objects

In object-oriented programming (OOP), a class is a blueprint or template for creating objects. An object is an instance of a class, with its own set of attributes (data) and methods (functions).

class Dog:
def __init__(self, name, breed):
    self.name = name
    self.breed = breed

def bark(self):
    print(f"{self.name} barks!")
dog1 = Dog("Buddy", "Golden Retriever")
dog1.bark()  # Output: Buddy barks!

Attributes and Methods

Attributes are variables associated with an object, representing its state or data. Methods are functions associated with an object, defining the behavior or actions it can perform.

class Circle:
def __init__(self, radius):
    self.radius = radius

def area(self):
    return 3.14 * (self.radius ** 2)

def circumference(self):
    return 2 * 3.14 * self.radius
circle1 = Circle(5)
print(circle1.area())       # Output: 78.5
print(circle1.circumference())  # Output: 31.4

Constructors (__init__)

The __init__ method is a special method in Python classes, known as the constructor. It is automatically called when an object is created from the class, and it is used to initialize the object's attributes with specific values.

class Person:
def __init__(self, name, age):
    self.name = name
    self.age = age

def greet(self):
    print(f"Hello, my name is {self.name} and I'm {self.age} years old.")
person1 = Person("Alice", 25)
person1.greet()  # Output: Hello, my name is Alice and I'm 25 years old.

Inheritance

Inheritance is a fundamental concept in OOP, which allows a new class (child or derived class) to inherit attributes and methods from an existing class (parent or base class). This helps in code reusability and promotes the DRY (Don't Repeat Yourself) principle.

class Animal:
def __init__(self, name):
    self.name = name

def speak(self):
    print("The animal makes a sound.")
class Dog(Animal):
def speak(self):
print(f"{self.name} barks.")
class Cat(Animal):
def speak(self):
print(f"{self.name} meows.")
dog = Dog("Buddy")
dog.speak()  # Output: Buddy barks.
cat = Cat("Whiskers")
cat.speak()  # Output: Whiskers meows.

Polymorphism

Polymorphism is the ability of objects of different classes to respond to the same method call in different ways. This is achieved through method overriding in derived classes.

class Shape:
def area(self):
    pass
class Rectangle(Shape):
def init(self, length, width):
self.length = length
self.width = width
def area(self):
    return self.length * self.width
class Circle(Shape):
def init(self, radius):
self.radius = radius
def area(self):
    return 3.14 * (self.radius ** 2)
shapes = [Rectangle(5, 3), Circle(4)]
for shape in shapes:
print(shape.area())  # Output: 15, 50.24

Encapsulation

Encapsulation is the mechanism of hiding the internal implementation details of an object from the outside world. It helps in data abstraction and provides a secure way to access and modify object attributes.

class BankAccount:
def __init__(self, balance):
    self.__balance = balance  # Private attribute

def deposit(self, amount):
    self.__balance += amount

def withdraw(self, amount):
    if self.__balance >= amount:
        self.__balance -= amount
    else:
        print("Insufficient balance")

def get_balance(self):
    return self.__balance
account = BankAccount(1000)
account.deposit(500)
account.withdraw(200)
print(account.get_balance())  # Output: 1300

Abstract Classes and Methods

An abstract class is a class that cannot be instantiated and is intended to be subclassed by other classes. Abstract methods are methods declared in an abstract class but without an implementation. Derived classes must provide their own implementation for abstract methods.

from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self):
pass
@abstractmethod
def perimeter(self):
    pass
class Rectangle(Shape):
def init(self, length, width):
self.length = length
self.width = width
def area(self):
    return self.length * self.width

def perimeter(self):
    return 2 * (self.length + self.width)
rect = Rectangle(5, 3)
print(rect.area())       # Output: 15
print(rect.perimeter())  # Output: 16

In the next chapter, we'll explore exceptions and error handling in Python, which is an essential aspect of writing robust and maintainable code.