Python教程41:面向对象最佳实践

“代码是写给人看的,顺便让机器执行。”

经过前面的学习,我们掌握了OOP的所有特性。今天总结Python面向对象的最佳实践,帮助你写出更优质的代码。

1. SOLID原则

S - 单一职责原则(Single Responsibility)

一个类只做一件事:

 1# 不好:类职责太多
 2class User:
 3    def __init__(self, name):
 4        self.name = name
 5    
 6    def save_to_database(self):
 7        """保存用户"""
 8        pass
 9    
10    def send_email(self):
11        """发送邮件"""
12        pass
13
14# 好:职责分离
15class User:
16    def __init__(self, name):
17        self.name = name
18
19class UserRepository:
20    def save(self, user):
21        """保存用户"""
22        pass
23
24class EmailService:
25    def send(self, user):
26        """发送邮件"""
27        pass

O - 开闭原则(Open/Closed)

对扩展开放,对修改关闭:

 1# 好:使用多态扩展功能
 2class Shape:
 3    def area(self):
 4        pass
 5
 6class Circle(Shape):
 7    def __init__(self, radius):
 8        self.radius = radius
 9    
10    def area(self):
11        return 3.14 * self.radius ** 2
12
13# 添加新形状无需修改现有代码
14class Rectangle(Shape):
15    def __init__(self, width, height):
16        self.width = width
17        self.height = height
18    
19    def area(self):
20        return self.width * self.height

L - 里氏替换原则(Liskov Substitution)

子类必须能替换父类:

 1# 不好:违反里氏替换
 2class Bird:
 3    def fly(self):
 4        return "Flying"
 5
 6class Penguin(Bird):
 7    def fly(self):
 8        raise Exception("企鹅不会飞")  # 破坏了父类约定
 9
10# 好:正确的继承
11class Bird:
12    pass
13
14class FlyingBird(Bird):
15    def fly(self):
16        return "Flying"
17
18class Penguin(Bird):
19    def swim(self):
20        return "Swimming"

I - 接口隔离原则(Interface Segregation)

不应强迫实现不需要的方法:

 1# 不好:接口太大
 2class Worker:
 3    def work(self):
 4        pass
 5    
 6    def eat(self):
 7        pass
 8
 9# 好:接口分离
10class Workable:
11    def work(self):
12        pass
13
14class Eatable:
15    def eat(self):
16        pass
17
18class Human(Workable, Eatable):
19    def work(self):
20        return "Working"
21    
22    def eat(self):
23        return "Eating"
24
25class Robot(Workable):
26    def work(self):
27        return "Working"

D - 依赖倒置原则(Dependency Inversion)

依赖抽象而不是具体:

 1# 不好:依赖具体类
 2class MySQLDatabase:
 3    def save(self, data):
 4        pass
 5
 6class UserService:
 7    def __init__(self):
 8        self.db = MySQLDatabase()  # 硬编码依赖
 9
10# 好:依赖抽象
11class Database:
12    def save(self, data):
13        pass
14
15class MySQLDatabase(Database):
16    def save(self, data):
17        print("Save to MySQL")
18
19class UserService:
20    def __init__(self, database: Database):
21        self.db = database  # 依赖注入

2. 命名和组织

类命名

1# 使用大驼峰(PascalCase)
2class UserAccount:
3    pass
4
5class DataProcessor:
6    pass

方法命名

 1class Example:
 2    # 公开方法:小写+下划线
 3    def public_method(self):
 4        pass
 5    
 6    # 内部方法:单下划线开头
 7    def _internal_method(self):
 8        pass
 9    
10    # 私有方法:双下划线开头
11    def __private_method(self):
12        pass

组织原则

 1class WellOrganized:
 2    """
 3    良好组织的类:
 4    1. 类属性
 5    2. __init__
 6    3. 特殊方法(__str__, __repr__等)
 7    4. @property
 8    5. @classmethod
 9    6. @staticmethod
10    7. 公开方法
11    8. 私有方法
12    """
13    
14    # 1. 类属性
15    class_var = "类属性"
16    
17    # 2. 初始化
18    def __init__(self, value):
19        self.value = value
20    
21    # 3. 特殊方法
22    def __str__(self):
23        return f"Example({self.value})"
24    
25    # 4. Property
26    @property
27    def computed_value(self):
28        return self.value * 2
29    
30    # 5. 类方法
31    @classmethod
32    def from_string(cls, s):
33        return cls(int(s))
34    
35    # 6. 静态方法
36    @staticmethod
37    def utils_function():
38        pass
39    
40    # 7. 公开方法
41    def public_method(self):
42        pass
43    
44    # 8. 私有方法
45    def _private_method(self):
46        pass

3. 设计技巧

组合优于继承

 1# 不好:过度使用继承
 2class Animal: pass
 3class Mammal(Animal): pass
 4class Dog(Mammal): pass
 5
 6# 好:使用组合
 7class Engine:
 8    def start(self):
 9        pass
10
11class Car:
12    def __init__(self):
13        self.engine = Engine()  # 组合
14    
15    def start(self):
16        self.engine.start()

使用抽象基类定义接口

 1from abc import ABC, abstractmethod
 2
 3class PaymentProcessor(ABC):
 4    @abstractmethod
 5    def process_payment(self, amount):
 6        pass
 7
 8class CreditCardProcessor(PaymentProcessor):
 9    def process_payment(self, amount):
10        return f"Processing ${amount} with credit card"

使用属性而不是getter/setter

 1# 不好:Java风格
 2class Person:
 3    def get_age(self):
 4        return self._age
 5    
 6    def set_age(self, value):
 7        self._age = value
 8
 9# 好:Python风格
10class Person:
11    @property
12    def age(self):
13        return self._age
14    
15    @age.setter
16    def age(self, value):
17        if value < 0:
18            raise ValueError("年龄不能为负")
19        self._age = value

4. 文档和类型提示

 1from typing import List, Optional
 2
 3class User:
 4    """
 5    用户类
 6    
 7    Attributes:
 8        name: 用户名
 9        email: 邮箱地址
10    """
11    
12    def __init__(self, name: str, email: str):
13        """
14        初始化用户
15        
16        Args:
17            name: 用户名
18            email: 邮箱
19        """
20        self.name = name
21        self.email = email
22    
23    def send_email(self, message: str) -> bool:
24        """
25        发送邮件
26        
27        Args:
28            message: 邮件内容
29        
30        Returns:
31            是否发送成功
32        """
33        # 实现...
34        return True
35    
36    @classmethod
37    def from_dict(cls, data: dict) -> 'User':
38        """从字典创建用户"""
39        return cls(data['name'], data['email'])

5. 小结

Python OOP最佳实践:

  • SOLID原则:单一职责、开闭、里氏替换、接口隔离、依赖倒置
  • 命名规范:PascalCase类名、snake_case方法名
  • 设计技巧:组合优于继承、使用ABC、用property
  • 文档:类型提示、文档字符串

遵循这些实践能写出更优质、更Pythonic的OOP代码。


练习题

  1. 重构一段违反SOLID原则的代码
  2. 为现有类添加完整的类型提示和文档
  3. 将继承关系改为组合

本文代码示例

关注公众号:极客老墨

更多 AI 应用开发、工程实践和效率工具分享,欢迎扫码关注。

极客老墨微信公众号二维码

相关阅读