文章目录
- 一、类与实例:从抽象到具体
- 1️⃣ 类(Class):抽象的模板
- 2️⃣ 实例(Instance):具体的对象
- 3️⃣ `__init__` 方法:初始化实例属性
- 二、封装:数据与逻辑的“打包”
- 1️⃣ 方法的定义与调用
- 2️⃣ 私有属性:限制外部直接访问
- 三、继承:代码复用的利器
- 1️⃣ 基本用法
- 2️⃣ 继承的优势
- 四、多态:灵活的接口适配
- 1️⃣ 多态体现:
- 2️⃣ 优势
- 五、类属性与实例属性
- 1️⃣ 实例属性:每个实例独有
- 2️⃣ 类属性:类本身拥有,所有实例共享
- 六、对象信息的获取
- 七、鸭子类型 🦆
- ✅ 总结归纳
面向对象编程(OOP)是 Python 编程的核心思想之一,它通过封装、继承、多态等特性实现代码的复用与扩展。本文将系统梳理 Python 中 OOP 的核心概念,帮助你快速掌握面向对象编程的精髓。
一、类与实例:从抽象到具体
1️⃣ 类(Class):抽象的模板
类是对现实事物的抽象描述,定义了对象的属性(数据)和方法(行为)。使用 class
关键字定义,类名通常以大写字母开头,默认继承自 object
类(所有类的根类)。
class Student(object):# 类的属性和方法将在这里定义pass
2️⃣ 实例(Instance):具体的对象
实例是根据类创建的具体个体,每个实例拥有独立的数据。通过「类名 + ()」创建实例:
bart = Student()
lisa = Student()print(bart) # <__main__.Student object at 0x000001>
print(lisa) # <__main__.Student object at 0x000002>
3️⃣ __init__
方法:初始化实例属性
__init__
方法在创建实例时自动调用,用于初始化属性:
class Student(object):def __init__(self, name, score):self.name = nameself.score = scorebart = Student('Bart Simpson', 59)
lisa = Student('Lisa Simpson', 87)print(bart.name) # Bart Simpson
print(lisa.score) # 87
二、封装:数据与逻辑的“打包”
封装是将数据(属性)和操作数据的方法(函数)打包在一起,隐藏实现细节,仅通过公开方法访问。
1️⃣ 方法的定义与调用
class Student(object):def __init__(self, name, score):self.name = nameself.score = scoredef print_score(self):print(f"{self.name}: {self.score}")bart.print_score() # Bart Simpson: 59
2️⃣ 私有属性:限制外部直接访问
class Student(object):def __init__(self, name, score):self.__name = nameself.__score = scoredef get_name(self):return self.__namedef set_score(self, score):if 0 <= score <= 100:self.__score = scoreelse:raise ValueError("分数必须在 0-100 之间")
🔎 为什么使用私有属性?
- 避免外部修改敏感数据
- 封装实现细节,提高安全性和可靠性
三、继承:代码复用的利器
继承允许子类复用父类的属性和方法,并可扩展新功能或重写已有方法。
1️⃣ 基本用法
class Animal(object):def run(self):print("动物在奔跑...")class Dog(Animal):passclass Cat(Animal):def run(self):print("猫在奔跑...")
2️⃣ 继承的优势
dog = Dog()
dog.run() # 动物在奔跑...cat = Cat()
cat.run() # 猫在奔跑...
✅ 避免重复代码
✅ 子类可自定义行为
四、多态:灵活的接口适配
多态允许不同子类以统一接口调用,实现不同表现。
1️⃣ 多态体现:
def run_twice(animal):animal.run()animal.run()run_twice(Dog()) # 动物在奔跑...
run_twice(Cat()) # 猫在奔跑...class Tortoise(Animal):def run(self):print("乌龟在缓慢爬行...")run_twice(Tortoise()) # 乌龟在缓慢爬行...
2️⃣ 优势
- ✅ 调用方无需关心具体类型
- ✅ 遵循开闭原则:开放扩展,封闭修改
五、类属性与实例属性
1️⃣ 实例属性:每个实例独有
bart.age = 8
lisa.age = 9
2️⃣ 类属性:类本身拥有,所有实例共享
class Student(object):count = 0def __init__(self, name):self.name = nameStudent.count += 1bart = Student('Bart')
print(Student.count) # 1lisa = Student('Lisa')
print(Student.count) # 2
⚠️ 注意:实例属性会遮蔽同名类属性!
六、对象信息的获取
Python 提供丰富的内置函数动态获取对象信息:
函数 | 作用 |
---|---|
type(obj) | 获取类型 |
isinstance(obj, 类型) | 判断是否为某类或其子类实例 ✅ |
dir(obj) | 列出所有属性和方法 |
hasattr(obj, 'attr') | 判断是否有某属性 |
getattr(obj, 'attr') | 获取属性值,支持默认值 |
setattr(obj, 'attr', val) | 设置属性 |
✅示例:
class MyObject(object):def __init__(self):self.x = 9def power(self):return self.x * self.xobj = MyObject()print(hasattr(obj, 'x')) # True
print(getattr(obj, 'x')) # 9
print(getattr(obj, 'y', 404)) # 404
fn = getattr(obj, 'power')
print(fn()) # 81
七、鸭子类型 🦆
Python 作为动态语言,不依赖严格的继承关系,而是通过 “鸭子类型” 判断对象是否符合要求:“如果一个对象看起来像鸭子,叫起来像鸭子,那它就是鸭子”。
- 例如,只要一个对象有 read() 方法,就可以被视为 “类文件对象”,无需继承自某个特定的类:
def read(self):return "模拟文件内容"# 接收类文件对象的函数
def read_data(fp):print(fp.read())# 传入自定义的 FileLike 实例(无需继承)
read_data(FileLike()) # 模拟文件内容
💡 鸭子类型原则:只要有 .read()
方法,就可当作“类文件对象”使用!
✅ 总结归纳
OOP 概念 | 关键点说明 |
---|---|
类与实例 | 类是模板,实例是具体对象 |
__init__ | 初始化实例属性 |
封装 | 使用 __ 隐藏私有属性,避免滥用 |
方法调用 | 第一个参数为 self ,由实例自动传递 |
继承 | 子类继承父类,减少重复代码 |
多态 | 子类重写方法,接口统一,行为多样 |
类属性 | 所有实例共享 |
实例属性 | 各自独立 |
类型判断 | 推荐使用 isinstance() 判断 |
鸭子类型 | 行为决定角色,而非继承结构 |