Python 进阶详解:类与对象(Classes and Objects)—— 面向对象编程的核心
一、引言:什么是面向对象编程?
面向对象编程(OOP, Object-Oriented Programming) 是一种以“对象”为核心的编程范式,它通过 类(Class) 和 对象(Object) 来组织代码,支持 封装、继承、多态 三大核心特性。
Python 是一种完全支持 OOP 的语言,其语法简洁而强大,允许你用最少的代码实现复杂的功能。
核心概念:
✅ 使用 OOP 可以使代码更加 模块化、可复用、易于维护和扩展。
二、定义类
1. 基本语法
class 类名: \"\"\"文档字符串(可选)\"\"\" def __init__(self, 参数列表): \"\"\"初始化方法(构造函数)\"\"\" # 初始化实例属性 def 方法名(self, 参数列表): \"\"\"普通方法\"\"\" # 方法体
2. 示例:一个简单的 Person
类
python深色版本class Person: \"\"\"描述一个人的基本信息\"\"\" def __init__(self, name, age): self.name = name # 实例属性 self.age = age # 实例属性 def greet(self): print(f\"你好,我叫 {self.name},今年 {self.age} 岁。\")
✅ __init__
是构造函数,用于初始化新创建的对象状态。
✅ self
参数指向当前实例,必须作为第一个参数传递给所有实例方法。
三、创建对象(实例化)
创建类的实例称为“实例化”。
person1 = Person(\"Alice\", 25)person1.greet() # 输出:你好,我叫 Alice,今年 25 岁。
📌 每次调用 Person(...)
都会创建一个新的对象,彼此独立。
四、类的属性与方法
1. 实例属性 vs 类属性
类型
特点
作用范围
实例属性
每个实例都有自己的一份副本
实例独有
类属性
所有实例共享同一份数据
类级别共享
实例属性示例:
class Dog: def __init__(self, name): self.name = name # 每只狗有自己的名字dog1 = Dog(\"旺财\")dog2 = Dog(\"小黑\")print(dog1.name) # 旺财print(dog2.name) # 小黑
类属性示例:
class Dog: species = \"Canis familiaris\" # 所有狗共享这个物种 def __init__(self, name): self.name = namedog1 = Dog(\"旺财\")dog2 = Dog(\"小黑\")print(Dog.species) # Canis familiarisprint(dog1.species) # Canis familiaris(通过实例访问)
✅ 类属性适合存储所有实例共有的信息(如配置、常量)。
2. 实例方法 vs 类方法 vs 静态方法
方法类型
装饰器
第一个参数
用途
实例方法
无
self
(实例)
访问实例属性和方法
类方法
@classmethod
cls
(类)
创建工厂方法、操作类属性
静态方法
@staticmethod
无
工具函数,逻辑上属于类但不依赖实例或类
示例:
class MyClass: class_var = \"我是类变量\" def instance_method(self): print(f\"实例方法,访问 name={self.name}\") @classmethod def class_method(cls): print(f\"类方法,类名为 {cls.__name__},类变量={cls.class_var}\") @staticmethod def static_method(): print(\"这是一个静态方法,与类和实例无关\")# 使用示例obj = MyClass()obj.name = \"test\"obj.instance_method() # 实例方法MyClass.class_method() # 类方法MyClass.static_method() # 静态方法
✅ 推荐使用类方法实现“替代构造函数”:
@classmethoddef from_string(cls, data): name, age = data.split(\'-\') return cls(name, int(age))
五、继承(Inheritance)
继承允许一个类(子类)从另一个类(父类)派生属性和方法,实现代码复用和功能扩展。
1. 基本语法
class 子类名(父类名): pass
2. 示例:继承自 Person
的 Student
类
class Student(Person): def __init__(self, name, age, grade): super().__init__(name, age) # 调用父类构造函数 self.grade = grade # 新增属性 def study(self): print(f\"{self.name} 正在学习,年级为 {self.grade}。\")
✅ super()
是调用父类方法的标准方式,推荐使用。
3. 方法重写(Override)
子类可以重写父类的方法以提供特定实现。
class Student(Person): def greet(self): print(f\"你好,我是学生 {self.name},今年 {self.age} 岁,正在读 {self.grade} 年级。\")
✅ 保持接口一致,行为不同 —— 这正是多态的基础。
六、多态(Polymorphism)
多态意味着不同的类可以通过相同的接口调用,表现出不同的行为。
示例:动物叫声
class Animal: def speak(self): raise NotImplementedError(\"子类必须实现此方法\")class Dog(Animal): def speak(self): return \"汪汪!\"class Cat(Animal): def speak(self): return \"喵喵!\"# 多态函数def animal_sound(animal: Animal): print(animal.speak())# 测试dog = Dog()cat = Cat()animal_sound(dog) # 输出:汪汪!animal_sound(cat) # 输出:喵喵!
✅ 多态让代码更具灵活性和可扩展性,新增动物无需修改 animal_sound
函数。
七、封装(Encapsulation)
封装是将对象的内部状态隐藏起来,仅暴露有限的接口供外部访问,从而增强安全性和简化使用。
1. 使用私有属性和方法
在属性或方法名前加双下划线 __
表示私有成员(名称改写机制)。
class BankAccount: def __init__(self, balance=0): self.__balance = balance # 私有属性 def deposit(self, amount): if amount > 0: self.__balance += amount print(f\"存款 {amount} 元\") else: print(\"金额必须大于0\") def withdraw(self, amount): if 0 < amount <= self.__balance: self.__balance -= amount print(f\"取款 {amount} 元\") else: print(\"余额不足或金额无效\") def get_balance(self): return self.__balance # 提供只读访问
⚠️ Python 没有严格的访问控制(如 Java 的 private
),但 __
会触发名称改写(_ClassName__attribute
),起到“弱私有”作用。
✅ 推荐使用属性装饰器(@property
)来控制访问:
@propertydef balance(self): return self.__balance@balance.setterdef balance(self, value): if value >= 0: self.__balance = value else: print(\"余额不能为负数\")
八、总结:类与对象的核心要点
关键点
说明
定义类
使用 class
关键字,包含属性和方法
实例化
创建类的对象(实例)
属性
分为实例属性(每个对象独有)和类属性(共享)
方法
实例方法(self
)、类方法(@classmethod
, cls
)、静态方法(@staticmethod
)
继承
支持代码复用和扩展,使用 super()
调用父类方法
多态
不同类通过相同接口表现不同行为,提升灵活性
封装
保护对象内部状态,仅暴露必要接口,推荐使用 @property
九、最佳实践与建议
建议
说明
✅ 优先使用组合而非继承
更灵活,避免复杂的继承链
✅ 遵循单一职责原则
一个类只负责一个功能
✅ 使用 @property
控制属性访问
安全且优雅
✅ 合理设计类的接口
对外暴露最少必要方法
✅ 文档化你的类
使用 docstring 说明用途和用法
十、动手练习
1. 创建一个 Rectangle
类,包含计算面积和周长的方法
class Rectangle: 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)# 测试rect = Rectangle(4, 5)print(f\"面积:{rect.area()}\") # 20print(f\"周长:{rect.perimeter()}\") # 18
2. 设计一个 Shape
基类及两个子类 Circle
和 Square
,实现多态行为
import mathclass Shape: def area(self): raise NotImplementedError(\"子类必须实现 area 方法\")class Circle(Shape): def __init__(self, radius): self.radius = radius def area(self): return math.pi * self.radius ** 2class Square(Shape): def __init__(self, side): self.side = side def area(self): return self.side ** 2# 多态测试shapes = [Circle(3), Square(4)]for shape in shapes: print(f\"面积:{shape.area():.2f}\")# 输出:# 面积:28.27# 面积:16.00
3. 编写一个简单的银行账户系统,应用封装原则
class BankAccount: def __init__(self, owner, initial_balance=0): self.owner = owner self.__balance = initial_balance def deposit(self, amount): if amount > 0: self.__balance += amount print(f\"✅ {self.owner} 存款 {amount} 元\") else: print(\"❌ 存款金额必须大于0\") def withdraw(self, amount): if 0 < amount <= self.__balance: self.__balance -= amount print(f\"✅ {self.owner} 取款 {amount} 元\") else: print(\"❌ 余额不足或金额无效\") @property def balance(self): return self.__balance# 测试acc = BankAccount(\"张三\", 100)acc.deposit(50)acc.withdraw(30)acc.withdraw(200) # 余额不足print(f\"当前余额:{acc.balance} 元\") # 120 元
🚀 学习建议
- 多实践:尝试设计自己的类模型(如图书管理系统、学生信息管理)。
- 理解三大特性:深入掌握封装、继承、多态的原理和应用场景。
- 阅读优秀代码:学习标准库(如
datetime
,collections
)中的 OOP 设计。 - 进阶学习:
-
- 抽象基类(
abc.ABC
) - 特殊方法(
__str__
,__repr__
,__eq__
等) - 设计模式(工厂、单例、观察者等)
- 抽象基类(