Python supports classes, inheritance, polymorphism, and encapsulation. OOP helps organize code into reusable, logical structures.
Classes and Objects
Python
class Dog:
"""A simple Dog class."""
# Class attribute (shared by all instances)
species = "Canis familiaris"
def __init__(self, name, age, breed):
"""Initialize a new Dog instance."""
self.name = name # Instance attribute
self.age = age
self.breed = breed
self._tricks = [] # Convention: _ prefix = "private"
def bark(self):
"""Make the dog bark."""
return f"{self.name} says Woof!"
def learn_trick(self, trick):
self._tricks.append(trick)
def show_tricks(self):
return f"{self.name} knows: {', '.join(self._tricks)}"
def __str__(self):
"""String representation."""
return f"{self.name} ({self.breed}, {self.age} years old)"
def __repr__(self):
"""Developer representation."""
return f"Dog(name='{self.name}', age={self.age}, breed='{self.breed}')"
# Creating objects
buddy = Dog("Buddy", 3, "Golden Retriever")
max_dog = Dog("Max", 5, "German Shepherd")
print(buddy) # Buddy (Golden Retriever, 3 years old)
print(buddy.bark()) # Buddy says Woof!
buddy.learn_trick("sit")
buddy.learn_trick("shake")
print(buddy.show_tricks()) # Buddy knows: sit, shakeInheritance
Python
class Animal:
def __init__(self, name, sound):
self.name = name
self.sound = sound
def speak(self):
return f"{self.name} says {self.sound}!"
def __str__(self):
return f"{self.__class__.__name__}: {self.name}"
class Dog(Animal):
def __init__(self, name, breed):
super().__init__(name, sound="Woof") # Call parent constructor
self.breed = breed
def fetch(self, item):
return f"{self.name} fetches the {item}!"
class Cat(Animal):
def __init__(self, name, indoor=True):
super().__init__(name, sound="Meow")
self.indoor = indoor
def describe(self):
location = "indoor" if self.indoor else "outdoor"
return f"{self.name} is an {location} cat"
# Polymorphism — same method, different behavior
animals = [Dog("Rex", "Labrador"), Cat("Whiskers")]
for animal in animals:
print(animal.speak()) # Each animal speaks differently!
# Rex says Woof!
# Whiskers says Meow!Properties
Python
class Circle:
def __init__(self, radius):
self._radius = radius # "Private" attribute
@property
def radius(self):
"""Getter — access like an attribute."""
return self._radius
@radius.setter
def radius(self, value):
"""Setter — validate before setting."""
if value < 0:
raise ValueError("Radius cannot be negative")
self._radius = value
@property
def area(self):
"""Computed property (read-only)."""
import math
return math.pi * self._radius ** 2
@property
def circumference(self):
import math
return 2 * math.pi * self._radius
c = Circle(5)
print(c.radius) # 5 (calls getter)
print(c.area) # 78.539... (computed on access)
c.radius = 10 # Calls setter
# c.area = 100 # AttributeError (read-only)
# c.radius = -1 # ValueError: Radius cannot be negativeDataclasses (Python 3.7+)
Python
from dataclasses import dataclass, field
from typing import List
@dataclass
class User:
name: str
email: str
age: int
hobbies: List[str] = field(default_factory=list)
@property
def is_adult(self) -> bool:
return self.age >= 18
def greet(self) -> str:
return f"Hi, I'm {self.name}!"
# Auto-generates: __init__, __repr__, __eq__, and more
alice = User("Alice", "alice@example.com", 28, ["reading", "coding"])
bob = User("Bob", "bob@example.com", 25)
print(alice) # User(name='Alice', email='alice@example.com', age=28, hobbies=['reading', 'coding'])
print(alice == bob) # False (structural equality)
# Copy with modifications
older_alice = alice.replace(age=29)Dunder Methods
Python
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
def __mul__(self, scalar):
return Vector(self.x * scalar, self.y * scalar)
def __abs__(self):
return (self.x**2 + self.y**2)**0.5
def __eq__(self, other):
return self.x == other.x and self.y == other.y
def __repr__(self):
return f"Vector({self.x}, {self.y})"
v1 = Vector(1, 2)
v2 = Vector(3, 4)
print(v1 + v2) # Vector(4, 6)
print(v1 * 3) # Vector(3, 6)
print(abs(v1)) # 2.236...Knowledge Check
4 questions — test your understanding
1
What does __init__ do in a Python class?
2
What does super().__init__() do?
3
What is the @property decorator used for?
4
What does a dataclass automatically generate?
Next: Files and Error Handling