Python 面向对象编程(OOP)详解:一篇足矣(2026 年实用版)
前言:Python 的面向对象编程(OOP)是其核心特性之一,让代码更模块化、可复用、可维护。OOP 三大支柱:封装(Encapsulation)、继承(Inheritance)、多态(Polymorphism)。如果你是新手,别担心,我们从 0 基础开始,由浅入深。教程基于 Python 3.12+,包含代码示例(直接复制运行)。学完这篇,你能自信写出 80% 实际项目中的 OOP 代码。
我们分成这些模块学(建议按顺序):
- OOP 基础概念
- 类和对象创建
- 属性与方法
- 继承与多态
- 封装与访问控制
- 特殊方法(魔法方法)
- 类变量 vs 实例变量、静态/类方法
- 高级话题(抽象类、接口、多继承)
- 常见错误 & 最佳实践
- 小练习 & 面试题
1. OOP 基础概念(为什么用 OOP?)
- 类(Class):蓝图/模板,比如“汽车”类定义了所有汽车的共同特征(颜色、速度)和行为(开车、刹车)。
- 对象(Object):类的实例,比如一辆具体的“红色特斯拉”。
- 为什么用 OOP?
- 复用:写一次类,到处创建对象。
- 组织:大项目分模块。
- 抽象:隐藏复杂细节,只露接口。
- 生活比喻:类 = 手机模具,对象 = 你手里的 iPhone。
一句话:一切皆对象(Python 哲学),int、str、list 都是内置类。
2. 类和对象创建(最简单起步)
用 class 关键字定义类。
# 定义类(类名首字母大写,驼峰式)
class Dog:
pass # 空类,占位
# 创建对象(实例化)
my_dog = Dog() # my_dog 是 Dog 的实例
print(type(my_dog)) # 输出: <class '__main__.Dog'>
进阶:带初始化方法(__init__)。
class Dog:
def __init__(self, name, age): # self 是实例自身(必须第一个参数)
self.name = name # 实例属性
self.age = age
# 创建对象
my_dog = Dog("旺财", 3)
print(my_dog.name) # 输出: 旺财
Tips:__init__ 不是构造函数(Python 没有严格构造函数),而是初始化方法。类定义时不执行,实例化时自动调用。
3. 属性与方法(类的核心内容)
- 属性(Attribute):数据(如 name、age)。
- 方法(Method):行为(如 bark、run)。
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
def bark(self): # 方法,self 必备
print(f"{self.name} 汪汪叫!")
def run(self, speed):
print(f"{self.name} 以 {speed} km/h 跑!")
my_dog = Dog("旺财", 3)
my_dog.bark() # 输出: 旺财 汪汪叫!
my_dog.run(20) # 输出: 旺财 以 20 km/h 跑!
属性分类:
- 实例属性:每个对象独立(如 self.name)。
- 类属性:所有对象共享(见第 7 节)。
方法调用:总是 对象.方法(),内部用 self 访问属性。
4. 继承与多态(代码复用神器)
- 继承:子类继承父类属性/方法,可扩展/覆盖。
class Animal: # 父类(基类)
def __init__(self, species):
self.species = species
def eat(self):
print("吃东西...")
class Dog(Animal): # 子类(派生类),继承 Animal
def __init__(self, name, age):
super().__init__("狗") # 调用父类 __init__
self.name = name
self.age = age
def bark(self):
print(f"{self.name} 汪汪!")
def eat(self): # 方法覆盖(重写)
print(f"{self.name} 吃骨头!") # 多态体现
my_dog = Dog("旺财", 3)
my_dog.eat() # 输出: 旺财 吃骨头!(覆盖父类)
print(my_dog.species) # 输出: 狗(继承父类)
- 多态:不同子类用同名方法,行为不同(鸭子类型)。
class Cat(Animal):
def eat(self):
print("吃鱼!")
animals = [Dog("旺财", 3), Cat()] # Cat 需加 __init__,这里省略
for animal in animals:
animal.eat() # 多态:狗吃骨头,猫吃鱼
super():调用父类方法,Python 3 推荐无参数形式。
5. 封装与访问控制(隐藏细节)
- 封装:把数据/方法打包,隐藏内部实现。
- Python 无严格私有(约定俗成用 _ 或 __)。
| 访问级别 | 写法 | 说明 |
|---|---|---|
| 公有 | name | 外部可直接访问 |
| 保护(约定) | _name | 子类可访问,外部不建议 |
| 私有(伪) | __name | 名称改写为 _Class__name,外部难访问 |
class BankAccount:
def __init__(self, balance):
self.__balance = balance # 私有属性
def deposit(self, amount):
self.__balance += amount
def get_balance(self): # getter 方法
return self.__balance
account = BankAccount(100)
print(account.get_balance()) # 100
# print(account.__balance) # AttributeError(但可通过 _BankAccount__balance 访问,勿滥用)
@property(优雅 getter/setter,C++ 无等价):
class Circle:
def __init__(self, radius):
self.__radius = radius
@property
def radius(self):
return self.__radius
@radius.setter
def radius(self, value):
if value < 0:
raise ValueError("半径不能负")
self.__radius = value
c = Circle(5)
print(c.radius) # 5(像属性访问)
c.radius = 10 # setter 调用
6. 特殊方法(魔法方法,Python OOP 的灵魂)
这些以 __ 开头的双下划线方法,让类像内置类型一样行为。
| 常见魔法方法 | 作用 | 示例代码 |
|---|---|---|
| init | 初始化 | 如上 |
| str | print 时调用 | return f”Dog: {self.name}” |
| repr | repr() 或调试时 | return f”Dog(‘{self.name}’, {self.age})” |
| len | len(obj) | return 长度 |
| getitem | obj[key] | 支持索引如列表 |
| call | obj() 如函数调用 | def call(self): print(“调用!”) |
| add | obj1 + obj2 | return self.value + other.value |
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
def __str__(self):
return f"({self.x}, {self.y})"
v1 = Vector(1, 2)
v2 = Vector(3, 4)
print(v1 + v2) # 输出: (4, 6)
Tips:魔法方法让类“鸭子类型”兼容(如自定义类支持 + 操作符)。
7. 类变量 vs 实例变量、静态/类方法
- 类变量:类级共享,所有实例共用。
- 实例变量:每个实例独立。
class Dog:
species = "狗" # 类变量
def __init__(self, name):
self.name = name # 实例变量
d1 = Dog("旺财")
d2 = Dog("小黑")
print(d1.species, d2.species) # 狗 狗
Dog.species = "Canine" # 修改类变量,所有实例变
print(d1.species) # Canine
- 静态方法:不访问 self/class,用 @staticmethod。
- 类方法:访问类,用 @classmethod,第一个参数 cls。
class MathUtil:
@staticmethod
def add(a, b):
return a + b # 无 self/cls
@classmethod
def from_string(cls, s):
return cls() # cls 是类自身,可创建实例
print(MathUtil.add(1, 2)) # 3(像函数调用)
8. 高级话题(抽象类、接口、多继承)
- 抽象类:不能实例化,强制子类实现方法。用 abc 模块。
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self):
pass
class Rectangle(Shape):
def __init__(self, w, h):
self.w, self.h = w, h
def area(self):
return self.w * self.h
r = Rectangle(2, 3)
print(r.area()) # 6
# Shape() # TypeError: Can't instantiate abstract class
- 接口:Python 无正式接口,但用抽象类模拟(全抽象方法)。
- 多继承:支持,但小心菱形问题(MRO 方法解析顺序)。
class A: pass
class B: pass
class C(A, B): pass # 多继承
print(C.mro()) # [<class 'C'>, <class 'A'>, <class 'B'>, <class 'object'>]
菱形继承:用 super() 解决调用顺序。
9. 常见错误 & 最佳实践
| 错误类型 | 描述 & 修复 |
|---|---|
| 忘记 self | 方法参数漏 self → TypeError |
| 修改类变量误改实例 | self.species = “猫” 只改实例,非类 |
| init 拼写错 | int 等 → 不调用 |
| 继承时漏 super() | 父类属性未初始化 |
| 多继承 MRO 混乱 | 用 super(),检查 mro() |
最佳实践:
- 类小而专一(单一职责原则)。
- 用 dataclass (Python 3.7+) 简化 boilerplate。
- 优先组合 > 继承。
- 文档字符串(docstring)描述类/方法。
- 类型提示(typing 模块)提升可读性。
from dataclasses import dataclass
@dataclass
class Point:
x: int
y: int # 自动生成 __init__、__repr__ 等
10. 小练习 & 面试题
练习1:写一个 BankAccount 类,支持存款、取款、查询余额(用私有属性 + getter)。
练习2:实现一个 Shape 抽象类,子类 Circle 和 Rectangle 计算面积、周长。
面试题:
- 解释 self 和 cls 的区别?
- Python 如何实现多态?
- new 和 init 区别?(new 创建实例,init 初始化)
- 什么是元类(metaclass)?(类的类,type 是默认元类)
学完这些,你已掌握 Python OOP 90% 精髓!如果你想:
- 看完整练习答案?
- 深入某个话题(如元类、装饰器在 OOP 中的用)?
- 对比 Python OOP 与 C++/Java 的异同?
- 还是来点项目实战(如 OOP 实现的游戏)?
告诉我,继续陪你升级~ 😊