面向对象编程(OOP)现代教程
1. 面向对象编程概述
面向对象编程(Object-Oriented Programming,简称OOP)是以“实体交互”为核心的编程范式,它把数据(属性)和操作数据的逻辑(方法)绑定成一个独立的“对象”,用更贴近人类认知世界的方式组织代码——比如把“学生”看作有姓名、分数属性,还有“交作业”“打印成绩”方法的个体,而不是零散的变量和函数。
1.1 与面向过程编程的对比
为了直观理解OOP的优势,我们可以用一个简单的成绩管理场景对比两种范式:
2. Python中的OOP基础
Python是完全支持OOP的动态语言,但没有严格限制开发者必须用OOP——小脚本可以用面向过程,大型项目才更推荐。
2.1 类与对象
在Python中,类是创建对象的“模板/蓝图”,规定了对象应该有哪些属性、哪些方法;对象是类的“具体实例”,比如“学生模板”创建出的“张三”“李四”。
基础类定义
class Student:
"""学生类示例:记录姓名、分数并打印"""
# 初始化方法:创建对象时自动调用,self是指向当前对象的引用(必须写)
def __init__(self, name: str, score: float):
self.name = name # 实例属性:每个对象单独一份
self.score = score
# 实例方法:第一个参数也是self
def print_score(self) -> None:
"""打印格式化的成绩"""
print(f'📚 {self.name} 的成绩:{self.score}')
2.2 创建和使用对象
# 实例化两个Student对象
bart = Student('Bart Simpson', 59)
lisa = Student('Lisa Simpson', 87)
# 访问实例属性
print(f"Lisa的姓名:{lisa.name}") # 输出:📚 Lisa的姓名:Lisa Simpson
# 调用实例方法
bart.print_score() # 输出:📚 Bart Simpson 的成绩:59
lisa.print_score() # 输出:📚 Lisa Simpson 的成绩:87
3. 面向对象的三大核心特性
这是OOP区别于其他范式的关键,也是面试高频考点👇
3.1 封装(Encapsulation)
封装有两层含义:
- 数据绑定:把属性和方法装在一个类里
- 信息隐藏:对外只暴露必要的接口,内部实现细节(比如余额的计算逻辑)不能直接修改
Python用双下划线前缀__模拟私有属性/方法(注意是“模拟”,Python没有真正的私有,只是会自动重命名成_类名__属性名)。
封装示例:银行账户
class BankAccount:
def __init__(self, owner: str, initial_balance: float = 0.0):
self.owner = owner # 公开属性:可以直接访问
self.__balance = initial_balance # 私有属性:外部不能直接改
def deposit(self, amount: float) -> bool:
"""存款:验证金额合法性"""
if amount > 0:
self.__balance += amount
print(f"✅ 存款成功!当前余额:{self.__balance:.2f}")
return True
print("❌ 存款失败:金额必须大于0")
return False
def withdraw(self, amount: float) -> bool:
"""取款:验证金额合法性和余额"""
if 0 < amount <= self.__balance:
self.__balance -= amount
print(f"✅ 取款成功!当前余额:{self.__balance:.2f}")
return True
print(f"❌ 取款失败:金额无效或余额不足(当前:{self.__balance:.2f})")
return False
def get_balance(self) -> float:
"""对外唯一的余额查询接口"""
return self.__balance
3.2 继承(Inheritance)
继承就是子类复用父类的属性和方法,还可以重写(Override)父类的方法,或者新增子类特有的属性/方法。
Python支持多重继承(但不推荐滥用,容易造成菱形继承混乱)。
继承示例:Person→Student
class Person:
"""父类:通用的人类属性和方法"""
def __init__(self, name: str, age: int):
self.name = name
self.age = age
def introduce(self) -> str:
return f"👋 大家好,我是{self.name},今年{self.age}岁。"
# Student继承自Person(圆括号里写父类)
class Student(Person):
"""子类:新增学号、重写自我介绍"""
def __init__(self, name: str, age: int, student_id: str):
super().__init__(name, age) # super()调用父类的初始化方法
self.student_id = student_id # 新增子类属性
def introduce(self) -> str: # 重写父类方法
# 可以用super()复用父类的自我介绍内容
return f"{super().introduce()} 🎓 我的学号是{self.student_id}。"
3.3 多态(Polymorphism)
多态字面意思是“多种形态”,核心是不同类的对象,响应同一个消息(方法调用)时,会执行各自的逻辑。
实现多态的前提:
- 父类定义公共接口(可以是普通方法、抽象方法)
- 子类继承父类并重写接口
- 调用时只关心“父类类型”,不关心具体是哪个子类
多态示例:动物叫
class Animal:
"""父类:定义speak公共接口"""
def speak(self) -> str:
# 普通方法做公共接口:子类不重写会抛出异常
raise NotImplementedError("Animal的子类必须实现speak方法!")
class Dog(Animal):
def speak(self) -> str:
return "🐕 Woof! Woof!"
class Cat(Animal):
def speak(self) -> str:
return "🐱 Meow~ Meow~"
# 多态的使用:只接收Animal类型的参数
def make_animal_speak(animal: Animal) -> None:
print(animal.speak())
# 测试:传入不同的子类对象
dog = Dog()
cat = Cat()
make_animal_speak(dog) # 输出:🐕 Woof! Woof!
make_animal_speak(cat) # 输出:🐱 Meow~ Meow~
4. Python OOP高级特性
这些是Python特有的、能大幅提升开发效率的语法糖🍬
4.1 类方法与静态方法
除了实例方法,Python还有两种特殊方法:
- 类方法:用
@classmethod装饰,第一个参数是cls(指向当前类本身),可以访问/修改类属性
- 静态方法:用
@staticmethod装饰,第一个参数既不是self也不是cls,本质就是类里的普通函数
特殊方法示例
class Calculator:
# 类属性:所有对象共享一份
PI = 3.1415926535
def __init__(self, value: float):
self.value = value # 实例属性
@classmethod
def get_pi(cls) -> float:
"""类方法:获取π的值"""
return cls.PI
@classmethod
def set_pi(cls, new_pi: float) -> None:
"""类方法:修改π的值(所有对象都会受影响)"""
cls.PI = new_pi
@staticmethod
def add(a: float, b: float) -> float:
"""静态方法:简单的加法,不需要访问类或实例属性"""
return a + b
4.2 属性装饰器(@property)
如果想把方法变成“只读属性”,或者给属性加合法性检查,可以用@property。
属性装饰器示例:圆的半径和面积
class Circle:
def __init__(self, radius: float):
self._radius = radius # 用单下划线表示“受保护属性”(建议但不强制外部不直接访问)
@property
def radius(self) -> float:
"""把_get_radius变成只读属性"""
return self._radius
@radius.setter # 必须和@property装饰的方法同名
def radius(self, value: float) -> None:
"""给radius加设置检查"""
if value <= 0:
raise ValueError("❌ 半径必须是正数!")
self._radius = value
@property
def area(self) -> float:
"""只读的计算属性:不能设置,访问时自动计算"""
return self.PI * self._radius ** 2
# 类属性复用之前的Calculator.PI
PI = Calculator.get_pi()
4.3 抽象基类(ABC)
之前的Animal类用普通方法做公共接口,只有调用speak时才会报错;而抽象基类(ABC) 用@abstractmethod装饰的方法,在实例化抽象基类或未实现所有抽象方法的子类时就会报错,更安全。
抽象基类示例:图形
from abc import ABC, abstractmethod
class Shape(ABC): # 必须继承ABC
"""抽象基类:所有图形必须能计算面积和周长"""
@abstractmethod # 必须加这个装饰器
def area(self) -> float:
"""抽象方法:没有具体实现"""
pass
@abstractmethod
def perimeter(self) -> float:
pass
# Rectangle实现了所有抽象方法,可以实例化
class Rectangle(Shape):
def __init__(self, width: float, height: float):
self.width = width
self.height = height
def area(self) -> float:
return self.width * self.height
def perimeter(self) -> float:
return 2 * (self.width + self.height)
5. 现代Python OOP最佳实践
-
优先用组合而非继承:继承是“is-a”关系(比如“学生是人”),组合是“has-a”关系(比如“汽车有引擎”),组合更灵活、耦合度更低
# 组合示例
class Engine:
def start(self) -> None:
print("🚗 引擎启动!")
class Car:
def __init__(self):
self.engine = Engine() # Car类持有Engine的实例
def start(self) -> None:
self.engine.start()
-
用数据类(@dataclass)简化实体类(Python 3.7+):自动生成__init__、__repr__、__eq__等常用方法
from dataclasses import dataclass
@dataclass
class Point:
x: float
y: float
z: float = 0.0 # 支持默认值
-
始终加类型提示(Type Hints):提高代码可读性,IDE会自动补全和报错
# 类型提示示例
class Vector:
def __init__(self, x: float, y: float) -> None:
self.x = x
self.y = y
# 前向引用:Vector还没定义完时用'Vector'
def add(self, other: 'Vector') -> 'Vector':
return Vector(self.x + other.x, self.y + other.y)
-
遵循SOLID原则:大型项目的设计黄金法则(简单提下,不过多展开)
- 单一职责原则(SRP):一个类只做一件事
- 开闭原则(OCP):对扩展开放,对修改关闭
- 里氏替换原则(LSP):子类可以替换父类而不影响程序正确性
- 接口隔离原则(ISP):只给用户需要的接口
- 依赖倒置原则(DIP):依赖抽象而非具体实现
6. 总结
面向对象编程是现代软件开发的核心范式之一,Python提供了强大而灵活的OOP支持。掌握OOP的关键在于:
- 搞清楚类(模板)和对象(实例)的关系
- 熟练运用封装、继承、多态三大核心特性
- 灵活使用Python特有的OOP语法糖
- 大型项目遵循SOLID原则,优先用组合
通过良好的OOP设计,我们可以写出更模块化、可维护、可扩展的代码!