1. 面向对象编程的核心特性
作为一名有十年Python开发经验的工程师,我经常被问到面向对象编程(OOP)的核心概念。今天我想用最接地气的方式,结合大量实战案例,带大家彻底理解Python中面向对象的三大特性:封装、继承和多态。
面向对象不是Python独有的概念,但Python以其简洁的语法和灵活的特性,让OOP变得特别容易上手。在实际项目中,合理运用这三大特性,能让你的代码更加模块化、可维护性更高、扩展性更强。
注意:Python虽然是动态类型语言,但其OOP实现与其他静态类型语言(如Java、C++)有显著区别,特别是在私有成员处理和多重继承方面。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 封装:保护你的代码城堡
2.1 封装的概念与价值
封装就像给你的代码建一座城堡。城墙内的东西(属性和方法)受到保护,外部只能通过城门(公开接口)与城堡互动。这样做有几个明显的好处:
- 安全性:防止外部代码随意修改内部状态
- 可维护性:内部实现可以自由修改而不影响外部调用
- 易用性:对外提供简洁清晰的接口,隐藏复杂实现
在Python中,虽然没有严格的访问控制关键字,但通过命名约定实现了类似的封装效果。
2.2 Python的封装实现方式
Python使用下划线约定来实现不同级别的封装:
python复制class BankAccount:
def __init__(self, owner, balance):
self.owner = owner # 公开属性
self._balance = balance # 受保护属性(单下划线)
self.__pin = "1234" # 私有属性(双下划线)
# 公开方法
def deposit(self, amount):
if amount > 0:
self._balance += amount
self.__log_transaction(f"存入: {amount}")
else:
raise ValueError("存款金额必须大于0")
# 私有方法
def __log_transaction(self, message):
print(f"[交易日志] {message}")
# 通过property实现受保护属性的安全访问
@property
def balance(self):
return self._balance
2.2.1 命名约定的实际效果
- 单下划线前缀:约定为"受保护"成员,PEP8建议外部代码不要直接访问,但Python不会阻止
- 双下划线前缀:Python会进行名称修饰(name mangling),变成
_类名__属性名的形式,外部无法直接访问
python复制account = BankAccount("张三", 1000)
print(account.owner) # 正常访问
print(account._balance) # 可以访问但不建议
# print(account.__pin) # 报错:AttributeError
print(account._BankAccount__pin) # 可以访问但不应该这样做
2.3 封装的进阶技巧
2.3.1 使用property装饰器
Python的property装饰器可以让你更优雅地控制属性访问:
python复制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("温度不能低于绝对零度")
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
这样使用时既保持了直接属性访问的简洁性,又实现了数据验证:
python复制temp = Temperature(25)
print(temp.celsius) # 25
print(temp.fahrenheit) # 77.0
temp.fahrenheit = 100
print(temp.celsius) # 37.777...
2.3.2 使用描述符(Descriptor)
对于更复杂的属性控制,可以使用描述符:
python复制class PositiveNumber:
def __set_name__(self, owner, name):
self.name = name
def __get__(self, obj, objtype=None):
return obj.__dict__.get(self.name)
def __set__(self, obj, value):
if not isinstance(value, (int, float)) or value <= 0
