Python Object-Oriented Programming Explained
Basic Concepts of Classes and Objects
Class
A class is a template for creating objects, defining the attributes and methods of objects. A class is abstract and does not occupy memory.
Object
An object is an instance of a class, occupying memory and having specific attribute values.
pythonclass Person: def __init__(self, name, age): self.name = name # Instance attribute self.age = age def say_hello(self): # Instance method print(f"Hello, I'm {self.name}, {self.age} years old") # Create objects person1 = Person("Alice", 25) person2 = Person("Bob", 30) person1.say_hello() # Hello, I'm Alice, 25 years old person2.say_hello() # Hello, I'm Bob, 30 years old
Class Attributes vs Instance Attributes
Class Attributes
Class attributes belong to the class itself, and all instances share the same class attribute.
pythonclass Dog: species = "Canis familiaris" # Class attribute count = 0 # Class attribute def __init__(self, name): self.name = name # Instance attribute Dog.count += 1 dog1 = Dog("Buddy") dog2 = Dog("Max") print(dog1.species) # Canis familiaris print(dog2.species) # Canis familiaris print(Dog.count) # 2 # Modify class attribute Dog.species = "Canis lupus" print(dog1.species) # Canis lupus print(dog2.species) # Canis lupus
Instance Attributes
Instance attributes belong to individual object instances, each instance has its own independent copy.
pythonclass Car: def __init__(self, brand, color): self.brand = brand # Instance attribute self.color = color # Instance attribute car1 = Car("Toyota", "Red") car2 = Car("Honda", "Blue") print(car1.brand) # Toyota print(car2.brand) # Honda # Modify instance attribute car1.color = "Green" print(car1.color) # Green print(car2.color) # Blue
Method Types
Instance Methods
Instance methods are the most commonly used methods, with the first parameter being self, representing the object itself.
pythonclass Circle: def __init__(self, radius): self.radius = radius def area(self): # Instance method return 3.14159 * self.radius ** 2 def circumference(self): # Instance method return 2 * 3.14159 * self.radius circle = Circle(5) print(circle.area()) # 78.53975 print(circle.circumference()) # 31.4159
Class Methods
Class methods use the @classmethod decorator, with the first parameter being cls, representing the class itself.
pythonclass Person: count = 0 def __init__(self, name): self.name = name Person.count += 1 @classmethod def get_count(cls): # Class method return cls.count @classmethod def create_from_string(cls, name_str): # Class method as factory method name = name_str.strip().title() return cls(name) person1 = Person("Alice") person2 = Person.create_from_string(" bob ") print(Person.get_count()) # 2 print(person2.name) # Bob
Static Methods
Static methods use the @staticmethod decorator and don't require self or cls parameters.
pythonclass MathUtils: @staticmethod def add(a, b): # Static method return a + b @staticmethod def multiply(a, b): # Static method return a * b # Call directly through class print(MathUtils.add(3, 5)) # 8 print(MathUtils.multiply(4, 6)) # 24 # Can also call through object math_utils = MathUtils() print(math_utils.add(3, 5)) # 8
Inheritance
Single Inheritance
pythonclass Animal: def __init__(self, name): self.name = name def speak(self): pass class Dog(Animal): # Inherit from Animal class def speak(self): return f"{self.name} says Woof!" class Cat(Animal): # Inherit from Animal class def speak(self): return f"{self.name} says Meow!" dog = Dog("Buddy") cat = Cat("Whiskers") print(dog.speak()) # Buddy says Woof! print(cat.speak()) # Whiskers says Meow!
Multiple Inheritance
pythonclass Flyable: def fly(self): return "Flying" class Swimmable: def swim(self): return "Swimming" class Duck(Flyable, Swimmable): # Multiple inheritance def __init__(self, name): self.name = name def quack(self): return f"{self.name} says Quack!" duck = Duck("Donald") print(duck.fly()) # Flying print(duck.swim()) # Swimming print(duck.quack()) # Donald says Quack!
Method Resolution Order (MRO)
pythonclass A: def method(self): print("A") class B(A): def method(self): print("B") class C(A): def method(self): print("C") class D(B, C): # Multiple inheritance pass d = D() d.method() # B # View MRO print(D.__mro__) # (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
Polymorphism
Polymorphism allows objects of different classes to respond differently to the same message.
pythonclass Shape: 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.14159 * self.radius ** 2 def calculate_area(shape): return shape.area() # Polymorphism: Different objects call the same method rectangle = Rectangle(5, 3) circle = Circle(4) print(calculate_area(rectangle)) # 15 print(calculate_area(circle)) # 50.26544
Encapsulation
Encapsulation is binding data and methods that operate on the data together, and hiding internal implementation details.
Private Attributes and Methods
pythonclass BankAccount: def __init__(self, account_number, balance): self.account_number = account_number self.__balance = balance # Private attribute (double underscore) def deposit(self, amount): if amount > 0: self.__balance += amount return True return False def withdraw(self, amount): if 0 < amount <= self.__balance: self.__balance -= amount return True return False def get_balance(self): # Access private attribute return self.__balance def __validate_amount(self, amount): # Private method return amount > 0 account = BankAccount("123456", 1000) account.deposit(500) account.withdraw(200) print(account.get_balance()) # 1300 # Cannot directly access private attributes # print(account.__balance) # AttributeError
Property Decorators
pythonclass Temperature: def __init__(self, celsius): self.__celsius = celsius @property def celsius(self): # getter return self.__celsius @celsius.setter def celsius(self, value): # setter if value < -273.15: raise ValueError("Temperature below absolute zero") self.__celsius = value @property def fahrenheit(self): # Read-only property return self.__celsius * 9/5 + 32 temp = Temperature(25) print(temp.celsius) # 25 print(temp.fahrenheit) # 77.0 temp.celsius = 30 print(temp.celsius) # 30 # temp.celsius = -300 # ValueError
Abstract Classes and Interfaces
Abstract Base Classes (ABC)
pythonfrom abc import ABC, abstractmethod class Animal(ABC): # Abstract base class @abstractmethod def speak(self): # Abstract method pass @abstractmethod def move(self): # Abstract method pass class Dog(Animal): def speak(self): return "Woof!" def move(self): return "Running" class Cat(Animal): def speak(self): return "Meow!" def move(self): return "Prowling" # Cannot directly instantiate abstract class # animal = Animal() # TypeError dog = Dog() cat = Cat() print(dog.speak()) # Woof! print(cat.move()) # Prowling
Special Methods (Magic Methods)
Common Special Methods
pythonclass Vector: def __init__(self, x, y): self.x = x self.y = y def __str__(self): # String representation return f"Vector({self.x}, {self.y})" def __repr__(self): # Developer representation return f"Vector(x={self.x}, y={self.y})" def __add__(self, other): # Addition operation return Vector(self.x + other.x, self.y + other.y) def __eq__(self, other): # Equality comparison return self.x == other.x and self.y == other.y def __len__(self): # Length return int((self.x ** 2 + self.y ** 2) ** 0.5) v1 = Vector(3, 4) v2 = Vector(1, 2) print(v1) # Vector(3, 4) print(repr(v1)) # Vector(x=3, y=4) print(v1 + v2) # Vector(4, 6) print(v1 == Vector(3, 4)) # True print(len(v1)) # 5
Context Managers
pythonclass FileManager: def __init__(self, filename, mode): self.filename = filename self.mode = mode self.file = None def __enter__(self): # Enter context self.file = open(self.filename, self.mode) return self.file def __exit__(self, exc_type, exc_val, exc_tb): # Exit context if self.file: self.file.close() return False # Use context manager with FileManager("example.txt", "w") as f: f.write("Hello, World!") # File automatically closed
Design Patterns
Singleton Pattern
pythonclass Singleton: _instance = None def __new__(cls): if cls._instance is None: cls._instance = super().__new__(cls) return cls._instance s1 = Singleton() s2 = Singleton() print(s1 is s2) # True
Factory Pattern
pythonfrom abc import ABC, abstractmethod class Animal(ABC): @abstractmethod def speak(self): pass class Dog(Animal): def speak(self): return "Woof!" class Cat(Animal): def speak(self): return "Meow!" class AnimalFactory: @staticmethod def create_animal(animal_type): if animal_type == "dog": return Dog() elif animal_type == "cat": return Cat() else: raise ValueError(f"Unknown animal type: {animal_type}") dog = AnimalFactory.create_animal("dog") cat = AnimalFactory.create_animal("cat") print(dog.speak()) # Woof! print(cat.speak()) # Meow!
Best Practices
1. Use Composition Over Inheritance
python# Bad practice - Overusing inheritance class FlyingDog(Dog, Flyable): pass # Good practice - Using composition class Robot: def __init__(self, flying_ability): self.flying_ability = flying_ability def fly(self): return self.flying_ability.fly() class FlyingAbility: def fly(self): return "Flying" robot = Robot(FlyingAbility()) print(robot.fly()) # Flying
2. Follow SOLID Principles
python# Single Responsibility Principle class User: def __init__(self, name, email): self.name = name self.email = email class UserRepository: def save(self, user): pass class EmailService: def send_email(self, user, message): pass
3. Use Type Hints
pythonfrom typing import List, Optional class Product: def __init__(self, name: str, price: float): self.name = name self.price = price def get_discounted_price(self, discount: float) -> float: return self.price * (1 - discount) class ShoppingCart: def __init__(self): self.items: List[Product] = [] def add_item(self, product: Product) -> None: self.items.append(product) def get_total(self) -> float: return sum(item.price for item in self.items)
Summary
Core concepts of Python object-oriented programming:
- Classes and Objects: Classes are templates, objects are instances
- Attributes and Methods: Class attributes are shared, instance attributes are independent; instance methods, class methods, static methods
- Inheritance: Single inheritance, multiple inheritance, Method Resolution Order (MRO)
- Polymorphism: Different objects respond differently to the same message
- Encapsulation: Hide internal implementation, provide public interface
- Abstract Classes: Define interface specifications, force subclasses to implement
- Special Methods: Implement operator overloading, context management, etc.
- Design Patterns: Common patterns like Singleton, Factory, etc.
Mastering object-oriented programming enables writing code with clear structure, easy maintenance, and extensibility.