引言
面向对象编程(Object-Oriented Programming, OOP)是现代软件开发的核心范式之一。在Python中,OOP不仅提供了强大的代码组织能力,还通过封装、继承和多态等特性,帮助开发者构建可维护、可扩展的应用程序。本文将深入探讨Python中OOP的核心概念、高级特性以及实际应用,帮助读者从基础理解到高级实践。
1. 类与对象的基础
1.1 类的定义与实例化
在Python中,类是创建对象的蓝图。它定义了对象的属性和方法。以下是一个简单的类定义示例:
class Dog:
# 类属性(所有实例共享)
species = "Canis familiaris"
def __init__(self, name, age):
# 实例属性(每个实例独有)
self.name = name
self.age = age
def bark(self):
return f"{self.name} says woof!"
def describe(self):
return f"{self.name} is {self.age} years old"
# 创建实例
dog1 = Dog("Buddy", 3)
dog2 = Dog("Max", 5)
print(dog1.bark()) # Buddy says woof!
print(dog2.describe()) # Max is 5 years old
print(Dog.species) # Canis familiaris
关键点:
__init__方法是构造函数,在创建实例时自动调用self参数指向实例本身- 类属性被所有实例共享,实例属性每个实例独有
1.2 实例方法、类方法与静态方法
Python提供了三种方法类型,各有不同的用途:
class Calculator:
# 实例方法 - 操作实例数据
def __init__(self):
self.result = 0
def add(self, x):
self.result += x
return self.result
# 类方法 - 操作类数据(使用cls)
@classmethod
def get_description(cls):
return f"This is a {cls.__name__} class"
# 静态方法 - 独立于类和实例
@staticmethod
def multiply(x, y):
return x * y
# 使用示例
calc = Calculator()
print(calc.add(5)) # 5
print(Calculator.get_description()) # This is a Calculator class
print(Calculator.multiply(3, 4)) # 12
方法类型对比:
| 方法类型 | 装饰器 | 第一个参数 | 访问权限 |
|---|---|---|---|
| 实例方法 | 无 | self | 可访问实例和类属性 |
| 类方法 | @classmethod | cls | 只能访问类属性 |
| 静态方法 | @staticmethod | 无 | 不能访问实例或类属性 |
2. 封装与访问控制
2.1 Python的访问控制机制
Python通过命名约定实现访问控制,而不是严格的私有化:
class BankAccount:
def __init__(self, account_holder, initial_balance):
self.account_holder = account_holder # 公共属性
self._balance = initial_balance # 受保护属性(约定)
self.__pin = "1234" # 私有属性(名称修饰)
# 公共方法
def get_balance(self):
return self._balance
# 私有方法
def __verify_pin(self, pin):
return pin == self.__pin
def withdraw(self, amount, pin):
if self.__verify_pin(pin):
if amount <= self._balance:
self._balance -= amount
return f"Withdrew {amount}. New balance: {self._balance}"
return "Insufficient funds"
return "Invalid PIN"
# 使用示例
account = BankAccount("Alice", 1000)
print(account.account_holder) # Alice - 公共属性可访问
print(account._balance) # 1000 - 约定保护,但技术上可访问
# print(account.__pin) # AttributeError - 私有属性不可直接访问
# print(account.__verify_pin("1234")) # AttributeError - 私有方法不可直接访问
print(account.withdraw(200, "1234")) # Withdrew 200. New balance: 1000
print(account.withdraw(100, "9999")) # Invalid PIN
Python名称修饰机制:
# Python解释器会将私有名称转换为:_类名__属性名
print(account._BankAccount__pin) # '1234' - 可以这样访问,但不推荐
2.2 使用property装饰器实现真正的封装
class Temperature:
def __init__(self, celsius):
self._celsius = celsius
@property
def celsius(self):
"""获取摄氏温度"""
return self._celsius
@celsius.setter
def celsius(self, value):
"""设置摄氏温度并验证"""
if value < -273.15:
raise ValueError("Temperature below absolute zero is impossible")
self._celsius = value
@property
def fahrenheit(self):
"""计算华氏温度"""
return (self._celsius * 9/5) + 32
@fahrenheit.setter
def fahrenheit(self, value):
"""通过华氏温度设置"""
self.celsius = (value - 32) * 5/9 # 使用celsius setter进行验证
# 使用示例
temp = Temperature(25)
print(temp.celsius) # 25
print(temp.fahrenheit) # 77.0
temp.celsius = 30
print(temp.fahrenheit) # 86.0
temp.fahrenheit = 100
print(temp.celsius) # 37.77777777777778
# 验证失败
try:
temp.celsius = -300
except ValueError as e:
print(e) # Temperature below absolute zero is impossible
3. 继承与多态
3.1 单继承与方法重写
class Animal:
def __init__(self, name, species):
self.name = name
self.species = species
def speak(self):
raise NotImplementedError("Subclasses must implement speak method")
def describe(self):
return f"{self.name} is a {self.species}"
class Cat(Animal):
def __init__(self, name, indoor=True):
super().__init__(name, "Felis catus")
self.indoor = indoor
def speak(self):
return "Meow"
def describe(self):
# 重写父类方法并扩展功能
base_desc = super().describe()
location = "indoor" if self.indoor else "outdoor"
return f"{base_desc} ({location})"
class Dog(Animal):
def __init__(self, name, breed):
super().__init__(name, "Canis familiaris")
self.breed = breed
def speak(self):
return "Woof!"
def fetch(self, item):
return f"{self.name} fetched {item}"
# 使用示例
animals = [
Cat("Whiskers"),
Dog("Buddy", "Golden Retriever"),
Cat("Mittens", indoor=False)
]
for animal in animals:
print(f"{animal.name}: {animal.speak()}")
print(f" {animal.describe()}")
if isinstance(animal, Dog):
print(f" {animal.fetch('ball')}")
3.2 多继承与MRO(方法解析顺序)
Python支持多继承,使用C3线性化算法确定方法解析顺序:
class Flyer:
def __init__(self, name):
self.name = name
def fly(self):
return f"{self.name} is flying"
class Swimmer:
def __init__(self, name):
self.name = name
def swim(self):
return f"{self.name} is swimming"
class FlyingFish(Flyer, Swimmer):
def __init__(self, name):
# 注意:两个父类都有__init__,需要明确调用
Flyer.__init__(self, name)
# Swimmer.__init__(self, name) # 如果调用会重复初始化name
def describe(self):
return f"{self.name} can both fly and swim"
# 使用示例
fish = FlyingFish("Swift")
print(fish.fly()) # Swift is flying
print(fish.swim()) # Swift is swimming
print(fish.describe()) # Swift can both fly and swim
# 查看MRO
print(FlyingFish.mro())
# [<class '__main__.FlyingFish'>, <class '__main__.Flyer'>, <class '__main__.Swimmer'>, <class 'object'>]
MRO冲突解决:
class A:
def method(self):
return "A"
class B(A):
def method(self):
return "B"
class C(A):
def method(self):
return "C"
class D(B, C):
pass
# D的MRO: D -> B -> C -> A -> object
print(D.mro()) # [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
d = D()
print(d.method()) # "B" - 按照MRO顺序找到第一个method
4. 高级OOP特性
4.1 抽象基类(ABC)
from abc import ABC, abstractmethod
import numbers
class Shape(ABC):
@abstractmethod
def area(self):
"""计算面积"""
pass
@abstractmethod
def perimeter(self):
"""计算周长"""
pass
def describe(self):
return f"Area: {self.area():.2f}, Perimeter: {self.perimeter():.2f}"
class Rectangle(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 Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14159 * self.radius ** 2
def perimeter(self):
return 2 * 3.14159 * self.radius
# 使用示例
shapes = [Rectangle(5, 3), Circle(4)]
for shape in shapes:
print(shape.describe())
# 尝试实例化未实现抽象方法的类会失败
try:
class BadShape(Shape):
pass
bad = BadShape()
except TypeError as e:
print(f"Error: {e}") # Can't instantiate abstract class BadShape...
4.2 魔术方法(Dunder Methods)
class Vector2D:
def __init__(self, x, y):
self.x = x
self.y = y
# 字符串表示
def __str__(self):
return f"Vector({self.x}, {self.y})"
def __repr__(self):
return f"Vector2D({self.x}, {y})"
# 算术运算
def __add__(self, other):
if isinstance(other, Vector2D):
return Vector2D(self.x + other.x, self.y + other.y)
return NotImplemented
def __sub__(self, other):
if isinstance(other, Vector2D):
return Vector2D(self.x - other.x, self.y - other.y)
return NotImplemented
def __mul__(self, scalar):
if isinstance(scalar, (int, float)):
return Vector2D(self.x * scalar, self.y * scalar)
return NotImplemented
def __rmul__(self, scalar):
return self.__mul__(scalar)
# 比较运算
def __eq__(self, other):
if isinstance(other, Vector2D):
return self.x == other.x and self.y == other.y
return False
def __lt__(self, other):
if isinstance(other, Vector2D):
return (self.x**2 + self.y**2) < (other.x**2 + other.y**2)
return NotImplemented
# 容器协议
def __len__(self):
return 2
def __getitem__(self, key):
if key == 0:
return self.x
elif key == 1:
return self.y
raise IndexError("Vector2D index out of range")
def __iter__(self):
return iter([self.x, self.y])
# 可调用对象
def __call__(self, other=None):
if other is None:
return self
return self.__mul__(other)
# 使用示例
v1 = Vector2D(3, 4)
v2 = Vector2D(1, 2)
print(v1) # Vector(3, 4)
print(v1 + v2) # Vector(4, 6)
print(2 * v1) # Vector(6, 8)
print(v1 * 2) # Vector(6, 8)
print(v1 == Vector2D(3, 4)) # True
print(len(v1)) # 2
print(v1[0], v1[1]) # 3 4
print(list(v1)) # [3, 4]
print(v1()) # Vector(3, 4)
print(v1(2)) # Vector(6, 8)
4.3 描述符(Descriptors)
描述符是实现了描述符协议的对象,用于控制属性访问:
class TypedProperty:
"""类型检查属性描述符"""
def __init__(self, name, expected_type, default=None):
self.name = "_" + name
self.expected_type = expected_type
self.default = default
def __get__(self, instance, owner):
if instance is None:
return self
return getattr(instance, self.name, self.default)
def __set__(self, instance, value):
if not isinstance(value, self.expected_type):
raise TypeError(f"{self.name} must be of type {self.expected_type}")
setattr(instance, self.name, value)
def __delete__(self, instance):
raise AttributeError(f"Cannot delete {self.name}")
class Product:
# 使用描述符定义属性
name = TypedProperty("name", str)
price = TypedProperty("price", (int, float), default=0.0)
quantity = TypedProperty("quantity", int, default=0)
def __init__(self, name, price, quantity):
self.name = name
self.price = price
self.quantity = quantity
def total_cost(self):
return self.price * self.quantity
# 使用示例
product = Product("Laptop", 999.99, 5)
print(product.name) # Laptop
print(product.price) # 999.99
print(product.total_cost()) # 4999.95
# 类型检查
try:
product.price = "expensive"
except TypeError as e:
print(e) # _price must be of type (<class 'int'>, <class 'float'>)
try:
bad_product = Product(123, 100, 5) # name必须是str
except TypeError as e:
print(e) # _name must be of type <class 'str'>
# 删除属性会失败
try:
del product.price
except AttributeError as e:
print(e) # Cannot delete _price
5. 设计模式在Python OOP中的应用
5.1 工厂模式
from abc import ABC, abstractmethod
class PaymentProcessor(ABC):
@abstractmethod
def process_payment(self, amount):
pass
class CreditCardProcessor(PaymentProcessor):
def __init__(self, card_number):
self.card_number = card_number
def process_payment(self, amount):
return f"Processing ${amount} via Credit Card {self.card_number[-4:]}"
class PayPalProcessor(PaymentProcessor):
def __init__(self, email):
self.email = email
def process_payment(self, amount):
return f"Processing ${amount} via PayPal account {self.email}"
class CryptoProcessor(PaymentProcessor):
def __init__(self, wallet_address):
self.wallet_address = wallet_address
def process_payment(self, amount):
return f"Processing ${amount} via Crypto wallet {self.wallet_address[:8]}..."
class PaymentProcessorFactory:
"""工厂类创建支付处理器"""
@staticmethod
def create_processor(payment_type, **kwargs):
processors = {
'credit_card': CreditCardProcessor,
'paypal': PayPalProcessor,
'crypto': CryptoProcessor
}
if payment_type not in processors:
raise ValueError(f"Unknown payment type: {payment_type}")
return processors[payment_type](**kwargs)
# 使用示例
factory = PaymentProcessorFactory
# 创建不同的支付处理器
processor1 = factory.create_processor('credit_card', card_number="1234-5678-9012-3456")
processor2 = factory.create_processor('paypal', email="user@example.com")
processor3 = factory.create_processor('crypto', wallet_address="0x1234567890abcdef")
print(processor1.process_payment(100)) # Processing $100 via Credit Card 3456
print(processor2.process_payment(50)) # Processing $50 via PayPal account user@example.com
print(processor3.process_payment(200)) # Processing $200 via Crypto wallet 0x123456...
5.2 观察者模式
class Subject:
"""被观察的对象"""
def __init__(self):
self._observers = []
self._state = None
def attach(self, observer):
if observer not in self._observers:
self._observers.append(observer)
def detach(self, observer):
try:
self._observers.remove(observer)
except ValueError:
pass
def notify(self):
for observer in self._observers:
observer.update(self._state)
def update_state(self, new_state):
self._state = new_state
self.notify()
class Observer(ABC):
@abstractmethod
def update(self, state):
pass
class EmailNotifier(Observer):
def update(self, state):
print(f"Email: System state changed to {state}")
class SMSNotifier(Observer):
def update(self, state):
print(f"SMS: System state changed to {state}")
class LogNotifier(Observer):
def update(self, state):
print(f"Log: System state changed to {state}")
# 使用示例
subject = Subject()
email_notifier = EmailNotifier()
sms_notifier = SMSNotifier()
log_notifier = LogNotifier()
subject.attach(email_notifier)
subject.attach(sms_notifier)
subject.attach(log_notifier)
print("=== State changed to 'ERROR' ===")
subject.update_state("ERROR")
print("\n=== Detach SMS, state changed to 'OK' ===")
subject.detach(sms_notifier)
subject.update_state("OK")
6. Python OOP最佳实践
6.1 组合优于继承原则
# 不好的设计:过度使用继承
class Employee:
def __init__(self, name, salary):
self.name = name
self.salary = salary
class Manager(Employee):
def __init__(self, name, salary, department):
super().__init__(name, salary)
self.department = department
def schedule_meeting(self):
return f"Manager {self.name} schedules meeting"
class Developer(Employee):
def __init__(self, name, salary, language):
super().__init__(name, salary)
self.language = language
def write_code(self):
return f"Developer {self.name} writes {self.language} code"
# 更好的设计:使用组合
class Role:
def __init__(self, role_name):
self.role_name = role_name
def perform_duties(self):
return f"Performing duties of {self.role_name}"
class ManagerRole(Role):
def __init__(self, department):
super().__init__("Manager")
self.department = department
def perform_duties(self):
return f"Managing department {self.department}"
class DeveloperRole(Role):
def __init__(self, language):
super().__init__("Developer")
self.language = language
def perform_duties(self):
return f"Writing {self.language} code"
class Employee:
def __init__(self, name, salary, role):
self.name = name
self.salary = salary
self.role = role
def do_work(self):
return f"{self.name} ({self.role.role_name}): {self.role.perform_duties()}"
# 使用组合的灵活性
manager = Employee("Alice", 80000, ManagerRole("Engineering"))
developer = Employee("Bob", 60000, DeveloperRole("Python"))
print(manager.do_work()) # Alice (Manager): Managing department Engineering
print(developer.do_work()) # Bob (Developer): Writing Python code
# 可以轻松改变角色
developer.role = ManagerRole("Sales")
print(developer.do_work()) # Bob (Manager): Managing department Sales
6.2 使用dataclass简化代码
from dataclasses import dataclass, field
from typing import List
@dataclass
class Student:
name: str
student_id: int
grades: List[float] = field(default_factory=list)
def add_grade(self, grade: float):
self.grades.append(grade)
def average(self):
return sum(self.grades) / len(self.grades) if self.grades else 0
def __str__(self):
return f"Student {self.name} (ID: {self.student_id}) - Avg: {self.average():.2f}"
# 使用示例
student1 = Student("Charlie", 1001)
student1.add_grade(85)
student1.add_grade(92)
student1.add_grade(78)
student2 = Student("Diana", 1002, [95, 88, 91])
print(student1) # Student Charlie (ID: 1001) - Avg: 85.00
print(student2) # Student Diana (ID: 1002) - Avg: 91.33
# 自动生成的比较方法
print(student1 == Student("Charlie", 1001, [85, 92, 78])) # True
7. 异常处理与OOP
7.1 自定义异常类
class InsufficientFundsError(Exception):
"""当账户余额不足时抛出"""
def __init__(self, balance, amount):
self.balance = balance
self.amount = amount
super().__init__(f"Insufficient funds: balance={balance}, attempted={amount}")
class InvalidAccountError(Exception):
"""当账户不存在时抛出"""
pass
class BankAccountV2:
def __init__(self, account_id, initial_balance=0):
self.account_id = account_id
self.balance = initial_balance
def withdraw(self, amount):
if amount > self.balance:
raise InsufficientFundsError(self.balance, amount)
self.balance -= amount
return self.balance
def deposit(self, amount):
if amount <= 0:
raise ValueError("Deposit amount must be positive")
self.balance += amount
return self.balance
class Bank:
def __init__(self):
self.accounts = {}
def create_account(self, account_id, initial_balance=0):
if account_id in self.accounts:
raise InvalidAccountError(f"Account {account_id} already exists")
self.accounts[account_id] = BankAccountV2(account_id, initial_balance)
return self.accounts[account_id]
def get_account(self, account_id):
if account_id not in self.accounts:
raise InvalidAccountError(f"Account {account_id} not found")
return self.accounts[account_id]
# 使用示例
bank = Bank()
try:
account = bank.create_account("ACC001", 1000)
print(f"Created account with balance: {account.balance}")
# 正常操作
account.withdraw(500)
print(f"After withdrawal: {account.balance}")
# 触发异常
account.withdraw(1000)
except InsufficientFundsError as e:
print(f"Error: {e}")
print(f" Balance: {e.balance}, Attempted: {e.amount}")
except InvalidAccountError as e:
print(f"Account error: {e}")
# 异常链
try:
account = bank.get_account("ACC999")
except InvalidAccountError as e:
try:
account = bank.create_account("ACC999", 0)
except InvalidAccountError as e2:
raise RuntimeError("Failed to handle account") from e2
8. 总结
Python的面向对象编程提供了强大而灵活的工具来构建复杂的软件系统。从基础的类和对象,到高级的描述符和设计模式,掌握这些概念将显著提升代码质量和开发效率。
关键要点回顾:
- 封装:使用property和命名约定保护数据完整性
- 继承:合理使用继承,优先考虑组合
- 多态:利用duck typing和抽象基类
- 高级特性:描述符、魔术方法、dataclass等
- 设计模式:工厂、观察者等模式解决常见问题
- 最佳实践:组合优于继承,清晰的异常处理
通过本文的详细示例和解释,读者应该能够在实际项目中应用这些OOP概念,编写出更加优雅、可维护的Python代码。# 深入理解Python中的面向对象编程:从基础到高级实践
引言
面向对象编程(Object-Oriented Programming, OOP)是现代软件开发的核心范式之一。在Python中,OOP不仅提供了强大的代码组织能力,还通过封装、继承和多态等特性,帮助开发者构建可维护、可扩展的应用程序。本文将深入探讨Python中OOP的核心概念、高级特性以及实际应用,帮助读者从基础理解到高级实践。
1. 类与对象的基础
1.1 类的定义与实例化
在Python中,类是创建对象的蓝图。它定义了对象的属性和方法。以下是一个简单的类定义示例:
class Dog:
# 类属性(所有实例共享)
species = "Canis familiaris"
def __init__(self, name, age):
# 实例属性(每个实例独有)
self.name = name
self.age = age
def bark(self):
return f"{self.name} says woof!"
def describe(self):
return f"{self.name} is {self.age} years old"
# 创建实例
dog1 = Dog("Buddy", 3)
dog2 = Dog("Max", 5)
print(dog1.bark()) # Buddy says woof!
print(dog2.describe()) # Max is 5 years old
print(Dog.species) # Canis familiaris
关键点:
__init__方法是构造函数,在创建实例时自动调用self参数指向实例本身- 类属性被所有实例共享,实例属性每个实例独有
1.2 实例方法、类方法与静态方法
Python提供了三种方法类型,各有不同的用途:
class Calculator:
# 实例方法 - 操作实例数据
def __init__(self):
self.result = 0
def add(self, x):
self.result += x
return self.result
# 类方法 - 操作类数据(使用cls)
@classmethod
def get_description(cls):
return f"This is a {cls.__name__} class"
# 静态方法 - 独立于类和实例
@staticmethod
def multiply(x, y):
return x * y
# 使用示例
calc = Calculator()
print(calc.add(5)) # 5
print(Calculator.get_description()) # This is a Calculator class
print(Calculator.multiply(3, 4)) # 12
方法类型对比:
| 方法类型 | 装饰器 | 第一个参数 | 访问权限 |
|---|---|---|---|
| 实例方法 | 无 | self | 可访问实例和类属性 |
| 类方法 | @classmethod | cls | 只能访问类属性 |
| 静态方法 | @staticmethod | 无 | 不能访问实例或类属性 |
2. 封装与访问控制
2.1 Python的访问控制机制
Python通过命名约定实现访问控制,而不是严格的私有化:
class BankAccount:
def __init__(self, account_holder, initial_balance):
self.account_holder = account_holder # 公共属性
self._balance = initial_balance # 受保护属性(约定)
self.__pin = "1234" # 私有属性(名称修饰)
# 公共方法
def get_balance(self):
return self._balance
# 私有方法
def __verify_pin(self, pin):
return pin == self.__pin
def withdraw(self, amount, pin):
if self.__verify_pin(pin):
if amount <= self._balance:
self._balance -= amount
return f"Withdrew {amount}. New balance: {self._balance}"
return "Insufficient funds"
return "Invalid PIN"
# 使用示例
account = BankAccount("Alice", 1000)
print(account.account_holder) # Alice - 公共属性可访问
print(account._balance) # 1000 - 约定保护,但技术上可访问
# print(account.__pin) # AttributeError - 私有属性不可直接访问
# print(account.__verify_pin("1234")) # AttributeError - 私有方法不可直接访问
print(account.withdraw(200, "1234")) # Withdrew 200. New balance: 1000
print(account.withdraw(100, "9999")) # Invalid PIN
Python名称修饰机制:
# Python解释器会将私有名称转换为:_类名__属性名
print(account._BankAccount__pin) # '1234' - 可以这样访问,但不推荐
2.2 使用property装饰器实现真正的封装
class Temperature:
def __init__(self, celsius):
self._celsius = celsius
@property
def celsius(self):
"""获取摄氏温度"""
return self._celsius
@celsius.setter
def celsius(self, value):
"""设置摄氏温度并验证"""
if value < -273.15:
raise ValueError("Temperature below absolute zero is impossible")
self._celsius = value
@property
def fahrenheit(self):
"""计算华氏温度"""
return (self._celsius * 9/5) + 32
@fahrenheit.setter
def fahrenheit(self, value):
"""通过华氏温度设置"""
self.celsius = (value - 32) * 5/9 # 使用celsius setter进行验证
# 使用示例
temp = Temperature(25)
print(temp.celsius) # 25
print(temp.fahrenheit) # 77.0
temp.celsius = 30
print(temp.fahrenheit) # 86.0
temp.fahrenheit = 100
print(temp.celsius) # 37.77777777777778
# 验证失败
try:
temp.celsius = -300
except ValueError as e:
print(e) # Temperature below absolute zero is impossible
3. 继承与多态
3.1 单继承与方法重写
class Animal:
def __init__(self, name, species):
self.name = name
self.species = species
def speak(self):
raise NotImplementedError("Subclasses must implement speak method")
def describe(self):
return f"{self.name} is a {self.species}"
class Cat(Animal):
def __init__(self, name, indoor=True):
super().__init__(name, "Felis catus")
self.indoor = indoor
def speak(self):
return "Meow"
def describe(self):
# 重写父类方法并扩展功能
base_desc = super().describe()
location = "indoor" if self.indoor else "outdoor"
return f"{base_desc} ({location})"
class Dog(Animal):
def __init__(self, name, breed):
super().__init__(name, "Canis familiaris")
self.breed = breed
def speak(self):
return "Woof!"
def fetch(self, item):
return f"{self.name} fetched {item}"
# 使用示例
animals = [
Cat("Whiskers"),
Dog("Buddy", "Golden Retriever"),
Cat("Mittens", indoor=False)
]
for animal in animals:
print(f"{animal.name}: {animal.speak()}")
print(f" {animal.describe()}")
if isinstance(animal, Dog):
print(f" {animal.fetch('ball')}")
3.2 多继承与MRO(方法解析顺序)
Python支持多继承,使用C3线性化算法确定方法解析顺序:
class Flyer:
def __init__(self, name):
self.name = name
def fly(self):
return f"{self.name} is flying"
class Swimmer:
def __init__(self, name):
self.name = name
def swim(self):
return f"{self.name} is swimming"
class FlyingFish(Flyer, Swimmer):
def __init__(self, name):
# 注意:两个父类都有__init__,需要明确调用
Flyer.__init__(self, name)
# Swimmer.__init__(self, name) # 如果调用会重复初始化name
def describe(self):
return f"{self.name} can both fly and swim"
# 使用示例
fish = FlyingFish("Swift")
print(fish.fly()) # Swift is flying
print(fish.swim()) # Swift is swimming
print(fish.describe()) # Swift can both fly and swim
# 查看MRO
print(FlyingFish.mro())
# [<class '__main__.FlyingFish'>, <class '__main__.Flyer'>, <class '__main__.Swimmer'>, <class 'object'>]
MRO冲突解决:
class A:
def method(self):
return "A"
class B(A):
def method(self):
return "B"
class C(A):
def method(self):
return "C"
class D(B, C):
pass
# D的MRO: D -> B -> C -> A -> object
print(D.mro()) # [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
d = D()
print(d.method()) # "B" - 按照MRO顺序找到第一个method
4. 高级OOP特性
4.1 抽象基类(ABC)
from abc import ABC, abstractmethod
import numbers
class Shape(ABC):
@abstractmethod
def area(self):
"""计算面积"""
pass
@abstractmethod
def perimeter(self):
"""计算周长"""
pass
def describe(self):
return f"Area: {self.area():.2f}, Perimeter: {self.perimeter():.2f}"
class Rectangle(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 Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14159 * self.radius ** 2
def perimeter(self):
return 2 * 3.14159 * self.radius
# 使用示例
shapes = [Rectangle(5, 3), Circle(4)]
for shape in shapes:
print(shape.describe())
# 尝试实例化未实现抽象方法的类会失败
try:
class BadShape(Shape):
pass
bad = BadShape()
except TypeError as e:
print(f"Error: {e}") # Can't instantiate abstract class BadShape...
4.2 魔术方法(Dunder Methods)
class Vector2D:
def __init__(self, x, y):
self.x = x
self.y = y
# 字符串表示
def __str__(self):
return f"Vector({self.x}, {self.y})"
def __repr__(self):
return f"Vector2D({self.x}, {y})"
# 算术运算
def __add__(self, other):
if isinstance(other, Vector2D):
return Vector2D(self.x + other.x, self.y + other.y)
return NotImplemented
def __sub__(self, other):
if isinstance(other, Vector2D):
return Vector2D(self.x - other.x, self.y - other.y)
return NotImplemented
def __mul__(self, scalar):
if isinstance(scalar, (int, float)):
return Vector2D(self.x * scalar, self.y * scalar)
return NotImplemented
def __rmul__(self, scalar):
return self.__mul__(scalar)
# 比较运算
def __eq__(self, other):
if isinstance(other, Vector2D):
return self.x == other.x and self.y == other.y
return False
def __lt__(self, other):
if isinstance(other, Vector2D):
return (self.x**2 + self.y**2) < (other.x**2 + other.y**2)
return NotImplemented
# 容器协议
def __len__(self):
return 2
def __getitem__(self, key):
if key == 0:
return self.x
elif key == 1:
return self.y
raise IndexError("Vector2D index out of range")
def __iter__(self):
return iter([self.x, self.y])
# 可调用对象
def __call__(self, other=None):
if other is None:
return self
return self.__mul__(other)
# 使用示例
v1 = Vector2D(3, 4)
v2 = Vector2D(1, 2)
print(v1) # Vector(3, 4)
print(v1 + v2) # Vector(4, 6)
print(2 * v1) # Vector(6, 8)
print(v1 * 2) # Vector(6, 8)
print(v1 == Vector2D(3, 4)) # True
print(len(v1)) # 2
print(v1[0], v1[1]) # 3 4
print(list(v1)) # [3, 4]
print(v1()) # Vector(3, 4)
print(v1(2)) # Vector(6, 8)
4.3 描述符(Descriptors)
描述符是实现了描述符协议的对象,用于控制属性访问:
class TypedProperty:
"""类型检查属性描述符"""
def __init__(self, name, expected_type, default=None):
self.name = "_" + name
self.expected_type = expected_type
self.default = default
def __get__(self, instance, owner):
if instance is None:
return self
return getattr(instance, self.name, self.default)
def __set__(self, instance, value):
if not isinstance(value, self.expected_type):
raise TypeError(f"{self.name} must be of type {self.expected_type}")
setattr(instance, self.name, value)
def __delete__(self, instance):
raise AttributeError(f"Cannot delete {self.name}")
class Product:
# 使用描述符定义属性
name = TypedProperty("name", str)
price = TypedProperty("price", (int, float), default=0.0)
quantity = TypedProperty("quantity", int, default=0)
def __init__(self, name, price, quantity):
self.name = name
self.price = price
self.quantity = quantity
def total_cost(self):
return self.price * self.quantity
# 使用示例
product = Product("Laptop", 999.99, 5)
print(product.name) # Laptop
print(product.price) # 999.99
print(product.total_cost()) # 4999.95
# 类型检查
try:
product.price = "expensive"
except TypeError as e:
print(e) # _price must be of type (<class 'int'>, <class 'float'>)
try:
bad_product = Product(123, 100, 5) # name必须是str
except TypeError as e:
print(e) # _name must be of type <class 'str'>
# 删除属性会失败
try:
del product.price
except AttributeError as e:
print(e) # Cannot delete _price
5. 设计模式在Python OOP中的应用
5.1 工厂模式
from abc import ABC, abstractmethod
class PaymentProcessor(ABC):
@abstractmethod
def process_payment(self, amount):
pass
class CreditCardProcessor(PaymentProcessor):
def __init__(self, card_number):
self.card_number = card_number
def process_payment(self, amount):
return f"Processing ${amount} via Credit Card {self.card_number[-4:]}"
class PayPalProcessor(PaymentProcessor):
def __init__(self, email):
self.email = email
def process_payment(self, amount):
return f"Processing ${amount} via PayPal account {self.email}"
class CryptoProcessor(PaymentProcessor):
def __init__(self, wallet_address):
self.wallet_address = wallet_address
def process_payment(self, amount):
return f"Processing ${amount} via Crypto wallet {self.wallet_address[:8]}..."
class PaymentProcessorFactory:
"""工厂类创建支付处理器"""
@staticmethod
def create_processor(payment_type, **kwargs):
processors = {
'credit_card': CreditCardProcessor,
'paypal': PayPalProcessor,
'crypto': CryptoProcessor
}
if payment_type not in processors:
raise ValueError(f"Unknown payment type: {payment_type}")
return processors[payment_type](**kwargs)
# 使用示例
factory = PaymentProcessorFactory
# 创建不同的支付处理器
processor1 = factory.create_processor('credit_card', card_number="1234-5678-9012-3456")
processor2 = factory.create_processor('paypal', email="user@example.com")
processor3 = factory.create_processor('crypto', wallet_address="0x1234567890abcdef")
print(processor1.process_payment(100)) # Processing $100 via Credit Card 3456
print(processor2.process_payment(50)) # Processing $50 via PayPal account user@example.com
print(processor3.process_payment(200)) # Processing $200 via Crypto wallet 0x123456...
5.2 观察者模式
class Subject:
"""被观察的对象"""
def __init__(self):
self._observers = []
self._state = None
def attach(self, observer):
if observer not in self._observers:
self._observers.append(observer)
def detach(self, observer):
try:
self._observers.remove(observer)
except ValueError:
pass
def notify(self):
for observer in self._observers:
observer.update(self._state)
def update_state(self, new_state):
self._state = new_state
self.notify()
class Observer(ABC):
@abstractmethod
def update(self, state):
pass
class EmailNotifier(Observer):
def update(self, state):
print(f"Email: System state changed to {state}")
class SMSNotifier(Observer):
def update(self, state):
print(f"SMS: System state changed to {state}")
class LogNotifier(Observer):
def update(self, state):
print(f"Log: System state changed to {state}")
# 使用示例
subject = Subject()
email_notifier = EmailNotifier()
sms_notifier = SMSNotifier()
log_notifier = LogNotifier()
subject.attach(email_notifier)
subject.attach(sms_notifier)
subject.attach(log_notifier)
print("=== State changed to 'ERROR' ===")
subject.update_state("ERROR")
print("\n=== Detach SMS, state changed to 'OK' ===")
subject.detach(sms_notifier)
subject.update_state("OK")
6. Python OOP最佳实践
6.1 组合优于继承原则
# 不好的设计:过度使用继承
class Employee:
def __init__(self, name, salary):
self.name = name
self.salary = salary
class Manager(Employee):
def __init__(self, name, salary, department):
super().__init__(name, salary)
self.department = department
def schedule_meeting(self):
return f"Manager {self.name} schedules meeting"
class Developer(Employee):
def __init__(self, name, salary, language):
super().__init__(name, salary)
self.language = language
def write_code(self):
return f"Developer {self.name} writes {self.language} code"
# 更好的设计:使用组合
class Role:
def __init__(self, role_name):
self.role_name = role_name
def perform_duties(self):
return f"Performing duties of {self.role_name}"
class ManagerRole(Role):
def __init__(self, department):
super().__init__("Manager")
self.department = department
def perform_duties(self):
return f"Managing department {self.department}"
class DeveloperRole(Role):
def __init__(self, language):
super().__init__("Developer")
self.language = language
def perform_duties(self):
return f"Writing {self.language} code"
class Employee:
def __init__(self, name, salary, role):
self.name = name
self.salary = salary
self.role = role
def do_work(self):
return f"{self.name} ({self.role.role_name}): {self.role.perform_duties()}"
# 使用组合的灵活性
manager = Employee("Alice", 80000, ManagerRole("Engineering"))
developer = Employee("Bob", 60000, DeveloperRole("Python"))
print(manager.do_work()) # Alice (Manager): Managing department Engineering
print(developer.do_work()) # Bob (Developer): Writing Python code
# 可以轻松改变角色
developer.role = ManagerRole("Sales")
print(developer.do_work()) # Bob (Manager): Managing department Sales
6.2 使用dataclass简化代码
from dataclasses import dataclass, field
from typing import List
@dataclass
class Student:
name: str
student_id: int
grades: List[float] = field(default_factory=list)
def add_grade(self, grade: float):
self.grades.append(grade)
def average(self):
return sum(self.grades) / len(self.grades) if self.grades else 0
def __str__(self):
return f"Student {self.name} (ID: {self.student_id}) - Avg: {self.average():.2f}"
# 使用示例
student1 = Student("Charlie", 1001)
student1.add_grade(85)
student1.add_grade(92)
student1.add_grade(78)
student2 = Student("Diana", 1002, [95, 88, 91])
print(student1) # Student Charlie (ID: 1001) - Avg: 85.00
print(student2) # Student Diana (ID: 1002) - Avg: 91.33
# 自动生成的比较方法
print(student1 == Student("Charlie", 1001, [85, 92, 78])) # True
7. 异常处理与OOP
7.1 自定义异常类
class InsufficientFundsError(Exception):
"""当账户余额不足时抛出"""
def __init__(self, balance, amount):
self.balance = balance
self.amount = amount
super().__init__(f"Insufficient funds: balance={balance}, attempted={amount}")
class InvalidAccountError(Exception):
"""当账户不存在时抛出"""
pass
class BankAccountV2:
def __init__(self, account_id, initial_balance=0):
self.account_id = account_id
self.balance = initial_balance
def withdraw(self, amount):
if amount > self.balance:
raise InsufficientFundsError(self.balance, amount)
self.balance -= amount
return self.balance
def deposit(self, amount):
if amount <= 0:
raise ValueError("Deposit amount must be positive")
self.balance += amount
return self.balance
class Bank:
def __init__(self):
self.accounts = {}
def create_account(self, account_id, initial_balance=0):
if account_id in self.accounts:
raise InvalidAccountError(f"Account {account_id} already exists")
self.accounts[account_id] = BankAccountV2(account_id, initial_balance)
return self.accounts[account_id]
def get_account(self, account_id):
if account_id not in self.accounts:
raise InvalidAccountError(f"Account {account_id} not found")
return self.accounts[account_id]
# 使用示例
bank = Bank()
try:
account = bank.create_account("ACC001", 1000)
print(f"Created account with balance: {account.balance}")
# 正常操作
account.withdraw(500)
print(f"After withdrawal: {account.balance}")
# 触发异常
account.withdraw(1000)
except InsufficientFundsError as e:
print(f"Error: {e}")
print(f" Balance: {e.balance}, Attempted: {e.amount}")
except InvalidAccountError as e:
print(f"Account error: {e}")
# 异常链
try:
account = bank.get_account("ACC999")
except InvalidAccountError as e:
try:
account = bank.create_account("ACC999", 0)
except InvalidAccountError as e2:
raise RuntimeError("Failed to handle account") from e2
8. 总结
Python的面向对象编程提供了强大而灵活的工具来构建复杂的软件系统。从基础的类和对象,到高级的描述符和设计模式,掌握这些概念将显著提升代码质量和开发效率。
关键要点回顾:
- 封装:使用property和命名约定保护数据完整性
- 继承:合理使用继承,优先考虑组合
- 多态:利用duck typing和抽象基类
- 高级特性:描述符、魔术方法、dataclass等
- 设计模式:工厂、观察者等模式解决常见问题
- 最佳实践:组合优于继承,清晰的异常处理
通过本文的详细示例和解释,读者应该能够在实际项目中应用这些OOP概念,编写出更加优雅、可维护的Python代码。
