docs(Python): 添加Python面向对象编程系列文章
新增三篇关于Python面向对象编程的文档: 1. 基础入门介绍类与对象概念 2. 进阶讲解属性管理与魔术方法 3. 深度解析底层原理与元编程 同时添加一篇scoop配置国内源的开发日记
This commit is contained in:
350
src/content/posts/Python/Python面向对象深度解析.md
Normal file
350
src/content/posts/Python/Python面向对象深度解析.md
Normal file
@@ -0,0 +1,350 @@
|
||||
---
|
||||
title: Python面向对象编程终极指南:原理、进阶与元编程
|
||||
published: 2026-01-19T22:53:40
|
||||
description: '一篇涵盖 Python 面向对象编程(OOP)所有核心细节的终极指南。从底层的对象模型、内存管理,到进阶的描述符、MRO 算法、元类编程及设计模式。'
|
||||
image: ''
|
||||
draft: false
|
||||
lang: ''
|
||||
category: Python
|
||||
tags:
|
||||
- Python
|
||||
- OOP
|
||||
- 核心原理
|
||||
- 元编程
|
||||
- 深度好文
|
||||
---
|
||||
|
||||
这是一篇旨在彻底讲透 Python 面向对象编程(OOP)的终极指南。我们将不再局限于基础语法,而是深入到 Python 的对象模型底层,探讨**元类**、**描述符**、**方法解析顺序 (MRO)** 以及**内存管理**等高级话题。
|
||||
|
||||
## 目录
|
||||
|
||||
1. **对象模型底层**:`__new__` vs `__init__`
|
||||
2. **深入属性系统**:`__slots__` 与 描述符协议
|
||||
3. **继承的奥秘**:多重继承、Mixin 与 C3 算法
|
||||
4. **接口与约束**:抽象基类 (ABC) 与 协议 (Protocol)
|
||||
5. **元编程 (Metaprogramming)**:动态创建类与元类
|
||||
6. **魔术方法大全**:模拟 Python 内置行为
|
||||
7. **内存管理与垃圾回收**
|
||||
|
||||
---
|
||||
|
||||
## 1. 对象模型底层:`__new__` vs `__init__`
|
||||
|
||||
很多人认为 `__init__` 是构造函数,其实不然。对象的创建过程分为两步:
|
||||
|
||||
1. **构造 (Construction)**:`__new__` 分配内存,创建对象实例。
|
||||
2. **初始化 (Initialization)**:`__init__` 给这个已经创建好的实例设置初始值。
|
||||
|
||||
### 1.1 `__new__` 方法
|
||||
|
||||
`__new__` 是一个静态方法(虽然不需要写 `@staticmethod`),它的第一个参数是 `cls`。它**必须**返回一个实例。
|
||||
|
||||
**应用场景**:
|
||||
* **不可变对象 (Immutable Objects)**:继承自 `str`, `int`, `tuple` 的子类,因为它们一旦创建就无法修改,所以必须在 `__new__` 中定制。
|
||||
* **单例模式 (Singleton)**:控制只创建一个实例。
|
||||
* **元类编程**。
|
||||
|
||||
```python
|
||||
class UpperStr(str):
|
||||
def __new__(cls, value):
|
||||
# 在对象创建前拦截,强制转换为大写
|
||||
return super().__new__(cls, value.upper())
|
||||
|
||||
s = UpperStr("hello")
|
||||
print(s) # HELLO (str 是不可变的,必须在 __new__ 处理)
|
||||
```
|
||||
|
||||
### 1.2 单例模式实现
|
||||
|
||||
```python
|
||||
class Singleton:
|
||||
_instance = None
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
if cls._instance is None:
|
||||
# 只有第一次调用时才真正创建对象
|
||||
cls._instance = super().__new__(cls)
|
||||
return cls._instance
|
||||
|
||||
a = Singleton()
|
||||
b = Singleton()
|
||||
print(a is b) # True
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 深入属性系统:`__slots__` 与 描述符
|
||||
|
||||
### 2.1 `__slots__`:内存优化
|
||||
|
||||
默认情况下,Python 对象使用字典 (`__dict__`) 存储属性。这提供了极大的灵活性,但对于创建数百万个小对象的场景,内存消耗巨大。
|
||||
|
||||
`__slots__` 告诉 Python:“这个类只有这些属性,不要创建 `__dict__`”。
|
||||
|
||||
```python
|
||||
class Pixel:
|
||||
__slots__ = ('x', 'y') # 锁定属性,禁止动态添加其他属性
|
||||
|
||||
def __init__(self, x, y):
|
||||
self.x = x
|
||||
self.y = y
|
||||
|
||||
p = Pixel(10, 20)
|
||||
# p.z = 30 # AttributeError: 'Pixel' object has no attribute 'z'
|
||||
```
|
||||
|
||||
**副作用**:
|
||||
* 对象不再有 `__dict__`。
|
||||
* 无法动态添加新属性。
|
||||
* 继承时如果不重复定义 `__slots__`,子类依然会有 `__dict__`。
|
||||
|
||||
### 2.2 描述符 (Descriptors)
|
||||
|
||||
这是 Python 属性魔法的**核心**。`@property`、类方法、静态方法,底层全都是描述符。
|
||||
|
||||
一个实现了 `__get__`, `__set__`, 或 `__delete__` 方法的**类**,就是一个描述符。
|
||||
|
||||
```python
|
||||
class Integer:
|
||||
"""数据描述符:强制属性必须是整数"""
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
def __get__(self, instance, owner):
|
||||
if instance is None:
|
||||
return self
|
||||
return instance.__dict__.get(self.name)
|
||||
|
||||
def __set__(self, instance, value):
|
||||
if not isinstance(value, int):
|
||||
raise ValueError(f"{self.name} must be an integer")
|
||||
instance.__dict__[self.name] = value
|
||||
|
||||
class Point:
|
||||
x = Integer("x") # 描述符实例作为类属性
|
||||
y = Integer("y")
|
||||
|
||||
def __init__(self, x, y):
|
||||
self.x = x # 触发 Integer.__set__
|
||||
self.y = y
|
||||
|
||||
p = Point(1, 2)
|
||||
# p.x = "hello" # ValueError: x must be an integer
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 继承的奥秘:多重继承、Mixin 与 MRO
|
||||
|
||||
### 3.1 多重继承与菱形问题
|
||||
|
||||
Python 支持多重继承。当一个类继承多个父类时,如果父类中有同名方法,Python 如何决定调用哪一个?
|
||||
|
||||
Python 2.3 之后引入了 **C3 线性化算法** 来计算 **MRO (Method Resolution Order)**。
|
||||
|
||||
```python
|
||||
class A:
|
||||
def say(self): print("A")
|
||||
|
||||
class B(A):
|
||||
def say(self): print("B")
|
||||
|
||||
class C(A):
|
||||
def say(self): print("C")
|
||||
|
||||
class D(B, C):
|
||||
pass
|
||||
|
||||
d = D()
|
||||
d.say() # 输出 B
|
||||
print(D.mro())
|
||||
# [<class 'D'>, <class 'B'>, <class 'C'>, <class 'A'>, <class 'object'>]
|
||||
```
|
||||
|
||||
**原则**:
|
||||
1. 子类优先于父类。
|
||||
2. 多个父类按照从左到右的顺序检查。
|
||||
3. 如果出现菱形继承(如上图,B和C都继承A),确保公共基类(A)最后被检查(但在 `object` 之前)。
|
||||
|
||||
### 3.2 Mixin 模式
|
||||
|
||||
Mixin(混入)是一种设计模式,利用多重继承给类添加单一功能的“插件”,而不需要建立严格的父子关系。
|
||||
|
||||
```python
|
||||
class JsonSerializableMixin:
|
||||
def to_json(self):
|
||||
import json
|
||||
return json.dumps(self.__dict__)
|
||||
|
||||
class User(JsonSerializableMixin):
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
u = User("Alice")
|
||||
print(u.to_json()) # {"name": "Alice"}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 接口与约束:ABC 与 Protocol
|
||||
|
||||
Python 是动态语言,通常不强制类型。但为了大型项目的健壮性,我们需要接口约束。
|
||||
|
||||
### 4.1 抽象基类 (Abstract Base Classes)
|
||||
|
||||
使用 `abc` 模块定义抽象基类,强制子类实现特定方法。
|
||||
|
||||
```python
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
class Shape(ABC):
|
||||
@abstractmethod
|
||||
def area(self):
|
||||
pass
|
||||
|
||||
class Circle(Shape):
|
||||
def __init__(self, r):
|
||||
self.r = r
|
||||
|
||||
def area(self):
|
||||
return 3.14 * self.r ** 2
|
||||
|
||||
# s = Shape() # TypeError: Can't instantiate abstract class
|
||||
c = Circle(5) # OK
|
||||
```
|
||||
|
||||
### 4.2 Protocol (鸭子类型的静态检查)
|
||||
|
||||
Python 3.8 引入了 `typing.Protocol`。它不需要继承,只要类实现了协议规定的方法,类型检查器(如 MyPy)就认为它符合要求。
|
||||
|
||||
```python
|
||||
from typing import Protocol
|
||||
|
||||
class Flyer(Protocol):
|
||||
def fly(self) -> None:
|
||||
...
|
||||
|
||||
class Bird:
|
||||
def fly(self): print("Bird flying")
|
||||
|
||||
class Plane:
|
||||
def fly(self): print("Plane flying")
|
||||
|
||||
def lift_off(obj: Flyer):
|
||||
obj.fly()
|
||||
|
||||
# Bird 和 Plane 不需要显式继承 Flyer
|
||||
lift_off(Bird())
|
||||
lift_off(Plane())
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 元编程 (Metaprogramming)
|
||||
|
||||
元编程是“编写写代码的代码”。在 Python 中,类也是对象,**元类 (Metaclass)** 就是用来创建类的类。
|
||||
|
||||
默认情况下,`type` 是所有类的元类。
|
||||
|
||||
`class` 关键字背后的逻辑:
|
||||
```python
|
||||
# class MyClass: pass
|
||||
# 等价于:
|
||||
MyClass = type('MyClass', (), {})
|
||||
```
|
||||
|
||||
### 自定义元类
|
||||
|
||||
自定义元类通常继承自 `type`,并重写 `__new__` 或 `__init__`。可以在类创建时修改类的定义(自动添加方法、验证属性等)。
|
||||
|
||||
```python
|
||||
class AutoDebugMeta(type):
|
||||
"""自动给类中的所有方法添加打印调试信息的元类"""
|
||||
def __new__(mcs, name, bases, attrs):
|
||||
new_attrs = {}
|
||||
for key, value in attrs.items():
|
||||
if callable(value) and not key.startswith("__"):
|
||||
# 包装函数
|
||||
def wrapper(*args, **kwargs):
|
||||
print(f"Calling {key}...")
|
||||
return value(*args, **kwargs)
|
||||
new_attrs[key] = wrapper
|
||||
else:
|
||||
new_attrs[key] = value
|
||||
|
||||
return super().__new__(mcs, name, bases, new_attrs)
|
||||
|
||||
class MyService(metaclass=AutoDebugMeta):
|
||||
def process(self):
|
||||
print("Processing...")
|
||||
|
||||
s = MyService()
|
||||
s.process()
|
||||
# 输出:
|
||||
# Calling process...
|
||||
# Processing...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 魔术方法大全
|
||||
|
||||
除了常见的 `__init__`, `__str__`,Python 提供了极其丰富的魔术方法。
|
||||
|
||||
### 属性访问控制
|
||||
* `__getattr__(self, name)`: 访问**不存在**的属性时调用(兜底)。
|
||||
* `__getattribute__(self, name)`: 访问**任何**属性时都会调用(拦截所有访问,慎用,易递归)。
|
||||
* `__setattr__(self, name, value)`: 设置属性时调用。
|
||||
|
||||
### 容器模拟
|
||||
* `__len__(self)`
|
||||
* `__getitem__(self, key)`
|
||||
* `__setitem__(self, key, value)`
|
||||
* `__delitem__(self, key)`
|
||||
* `__iter__(self)`
|
||||
* `__contains__(self, item)`: `in` 操作符。
|
||||
|
||||
### 上下文管理
|
||||
* `__enter__`, `__exit__`: `with` 语句支持。
|
||||
|
||||
### 调用
|
||||
* `__call__`: 让实例像函数一样被调用 `instance()`。
|
||||
|
||||
---
|
||||
|
||||
## 7. 内存管理与垃圾回收
|
||||
|
||||
Python 使用**引用计数 (Reference Counting)** 为主,**标记-清除 (Mark and Sweep)** 和 **分代回收 (Generational Collection)** 为辅的垃圾回收机制。
|
||||
|
||||
### 7.1 `__del__` 析构方法
|
||||
|
||||
当对象的引用计数降为 0 时,`__del__` 会被调用。
|
||||
|
||||
**警告**:尽量不要依赖 `__del__` 来进行资源释放(如关闭文件),因为在循环引用等复杂情况下,它可能不会被立即调用,甚至不会被调用。应使用上下文管理器 (`with`)。
|
||||
|
||||
### 7.2 弱引用 (Weak Reference)
|
||||
|
||||
`weakref` 模块允许创建不增加引用计数的引用。常用于缓存实现,避免对象无法被回收。
|
||||
|
||||
```python
|
||||
import weakref
|
||||
|
||||
class Data:
|
||||
def __del__(self):
|
||||
print("Data died")
|
||||
|
||||
d = Data()
|
||||
r = weakref.ref(d) # 创建弱引用
|
||||
|
||||
print(r()) # 获取对象: <__main__.Data object ...>
|
||||
del d # 删除唯一强引用,对象立即被回收,输出 "Data died"
|
||||
print(r()) # None
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 结语
|
||||
|
||||
Python 的面向对象远比表面看起来深奥。从简单的 `class` 定义,到背后的元类机制、描述符协议以及 C3 算法,Python 提供了一套逻辑自洽且极具扩展性的对象模型。
|
||||
|
||||
掌握这些细节,不仅能让你写出更高效、更健壮的代码,更能让你在阅读 Django, SQLAlchemy 等顶级框架源码时游刃有余。
|
||||
Reference in New Issue
Block a user