Classes and Object-Oriented Programming (OOP)¶
Python is an object-oriented language. Almost everything in Python is an object with properties and methods. A class is a blueprint for creating objects.
1. Defining a Class¶
Classes are created using the class keyword. The __init__() method is the constructor that runs whenever a new instance is instantiated.
Syntax¶
class ClassName:
def __init__(self, parameter1, parameter2):
self.attribute1 = parameter1
self.attribute2 = parameter2
def method_name(self):
# method statements
class Car:
def __init__(self, brand: str, model: str, year: int):
self.brand = brand
self.model = model
self.year = year
self.odometer_reading = 0
def get_description(self) -> str:
return f"{self.year} {self.brand} {self.model}"
def update_odometer(self, mileage: int):
if mileage >= self.odometer_reading:
self.odometer_reading = mileage
else:
print("Cannot roll back an odometer.")
# Create an object instance
my_car = Car("Toyota", "Camry", 2024)
print(my_car.get_description())
my_car.update_odometer(1500)
print("Mileage:", my_car.odometer_reading)
Understanding self¶
The self parameter is a reference to the current instance of the class. It is used to access variables and methods that belong to that specific instance.
Instance Variables vs Class Variables¶
- Instance variables: Unique to each instance (defined inside
__init__viaself.x). - Class variables: Shared among all instances of the class (defined directly under the
classheader).
class Employee:
# Class variable
company_name = "Tech Corp"
def __init__(self, name: str, salary: float):
# Instance variables
self.name = name
self.salary = salary
e1 = Employee("Alice", 75000)
e2 = Employee("Bob", 68000)
print(e1.company_name) # Tech Corp
print(e2.company_name) # Tech Corp
2. Inheritance and super()¶
Inheritance allows a new class (child/subclass) to inherit attributes and methods from an existing class (parent/superclass):
class ElectricCar(Car):
def __init__(self, brand: str, model: str, year: int, battery_size: int):
# Call parent constructor using super()
super().__init__(brand, model, year)
self.battery_size = battery_size
def describe_battery(self):
print(f"This car has a {self.battery_size}-kWh battery.")
my_tesla = ElectricCar("Tesla", "Model 3", 2025, 75)
print(my_tesla.get_description()) # Inherited method
my_tesla.describe_battery() # Subclass-specific method
3. Class Methods and Static Methods¶
@classmethod: Receives the class (cls) as its first argument rather than an instance (self). Often used for alternative constructors.@staticmethod: Does not receive an implicit first argument (selforcls). Behaves like a regular function scoped within the class.
class Date:
def __init__(self, year: int, month: int, day: int):
self.year = year
self.month = month
self.day = day
@classmethod
def from_string(cls, date_str: str):
year, month, day = map(int, date_str.split("-"))
return cls(year, month, day)
@staticmethod
def is_valid_month(month: int) -> bool:
return 1 <= month <= 12
d = Date.from_string("2026-09-14")
print(f"Year: {d.year}, Month: {d.month}, Day: {d.day}")
print("Is Month 9 Valid:", Date.is_valid_month(9))
4. Private Attributes and Name Mangling¶
Python does not have strict private access specifiers (private keyword). Instead: - _attribute: A convention indicating that an attribute is internal/private. - __attribute: Triggers name mangling, where Python renames the attribute to _ClassName__attribute to prevent accidental overriding in subclasses.
5. Dataclasses (@dataclass)¶
The dataclasses module provides a decorator to automatically generate special methods such as __init__(), __repr__(), and __eq__() on user-defined classes:
from dataclasses import dataclass
@dataclass
class Book:
title: str
author: str
price: float
isbn: str
book1 = Book("Fluent Python", "Luciano Ramalho", 49.99, "978-1491957660")
book2 = Book("Fluent Python", "Luciano Ramalho", 49.99, "978-1491957660")
# Auto-generated clean __repr__:
print(book1)
# Auto-generated value-based __eq__:
print(book1 == book2) # True