python中的魔术方法(双下划线)

文章目录

        • [1. 构造与初始化 (最基础)](#1. 构造与初始化 (最基础))
        • [2. 字符串表示 (打印与调试)](#2. 字符串表示 (打印与调试))
        • [3. 模拟容器行为 (让对象像列表/字典)](#3. 模拟容器行为 (让对象像列表/字典))
        • [4. 运算符重载 (让对象支持数学运算)](#4. 运算符重载 (让对象支持数学运算))
        • [5. callable 对象 (让对象像函数一样被调用)](#5. callable 对象 (让对象像函数一样被调用))
        • [6. 上下文管理器 (用于 with 语句)](#6. 上下文管理器 (用于 with 语句))
        • [7. 属性访问控制 (高级)](#7. 属性访问控制 (高级))

先声明一点,魔术方法以双下划线命名,但是双下划线命名的不一定就是魔术方法,还可能是内置属性,如 __main__

1. 构造与初始化 (最基础)
方法 作用 调用时机
__new__(cls, ...) 真正创建实例的方法。返回新对象。 __init__ 之前调用,用于控制实例创建(如单例模式)。
__init__(self, ...) 初始化实例。设置属性。 对象创建后立即调用(最常用)。
__del__(self) 析构方法。 对象被垃圾回收前调用(通常不推荐依赖它做资源清理)。

代码:

python 复制代码
class Demo:
    def __new__(cls):
        print("1. 创建对象")
        return super().__new__(cls)
    
    def __init__(self):
        print("2. 初始化对象")
2. 字符串表示 (打印与调试)
方法 作用 调用时机
__str__(self) 给用户看的字符串。 使用 print(obj)str(obj) 时。
__repr__(self) 给开发者看的字符串(调试用)。 在交互式命令行输入 objrepr(obj) 时。
__format__(self, spec) 自定义格式化。 使用 f"{obj:.2f}" 等格式字符串时。

最佳实践:repr 应该尽量返回能重现对象的代码(如 <Person('Alice', 20)>),而 str 应该是易读的文本(如 Alice, 20岁)。

3. 模拟容器行为 (让对象像列表/字典)

让你的类支持索引、长度计算和迭代。

python 复制代码
方法 | 作用 | 对应操作
:--- | :--- | :---
`__len__(self)` | 返回长度。 | `len(obj)`
`__getitem__(self, key)` | 获取元素。 | `obj[key]`
`__setitem__(self, key, value)` | 设置元素。 | `obj[key] = value`
`__delitem__(self, key)` | 删除元素。 | `del obj[key]`
`__contains__(self, item)` | 检查是否存在。 | `item in obj`
`__iter__(self)` | 返回迭代器。 | `for x in obj:` (开始迭代)
`__next__(self)` | 返回下一个值。 | 迭代过程中自动调用

代码:

python 复制代码
class MyList:
    def __init__(self):
        self.data = [1, 2, 3]
    
    def __len__(self):
        return len(self.data)
    
    def __getitem__(self, index):
        return self.data[index]

l = MyList()
print(len(l))      # 调用 __len__ -> 3
print(l[0])        # 调用 __getitem__ -> 1
4. 运算符重载 (让对象支持数学运算)

让你的对象可以使用 +, -, *, > 等符号。

算术运算

python 复制代码
| 方法 | 操作 | 方法 | 操作 |
| :--- | :--- | :--- | :--- |
| `__add__(self, other)` | `a + b` | `__sub__(self, other)` | `a - b` |
| `__mul__(self, other)` | `a * b` | `__truediv__(self, other)` | `a / b` |
| `__floordiv__(self, other)` | `a // b` | `__mod__(self, other)` | `a % b` |
| `__pow__(self, other)` | `a  b` | | |

比较运算

方法 操作 方法 操作
__eq__(self, other) a == b __ne__(self, other) a != b
__lt__(self, other) a < b __le__(self, other) a <= b
__gt__(self, other) a > b __ge__(self, other) a >= b

代码:

python 复制代码
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 __eq__(self, other):
        return self.x == other.x and self.y == other.y
    
    def __str__(self):
        return f"Vector({self.x}, {self.y})"

v1 = Vector(1, 2)
v2 = Vector(3, 4)
print(v1 + v2)  # 调用 __add__ -> Vector(4, 6)
print(v1 == v2) # 调用 __eq__ -> False
5. callable 对象 (让对象像函数一样被调用)
方法 作用 对应操作
__call__(self, ...) 让实例可以像函数一样执行。 obj()

代码:

python 复制代码
class Multiplier:
    def __init__(self, factor):
        self.factor = factor
    
    def __call__(self, value):
        return value * self.factor

double = Multiplier(2)
print(double(5))  # 输出 10,就像调用函数 double(5)
6. 上下文管理器 (用于 with 语句)

让你的类支持 with open(...) as f: 这种语法,自动管理资源(如文件关闭、锁释放)。

方法 作用
__enter__(self) 进入 with 块时执行,返回值赋给 as 后面的变量。
__exit__(self, exc_type, exc_val, exc_tb) 离开 with 块时执行(无论是否发生异常)。

代码:

python 复制代码
class MyResource:
    def __enter__(self):
        print("资源打开")
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("资源关闭")
        # 返回 True 可以吞掉异常,返回 False (或 None) 则抛出异常

with MyResource() as res:
    print("正在使用资源")
7. 属性访问控制 (高级)

拦截对属性的读取、设置和删除操作。

方法 作用
__getattr__(self, name) 当访问不存在的属性时触发。
__setattr__(self, name, value) 每次设置任何属性时都触发(小心死循环)。
__getattribute__(self, name) 每次访问任何属性时都触发(优先级最高,慎用)。
__delattr__(self, name) 删除属性时触发。

总结:什么时候用?

日常开发:最常用的是 init , str , repr , eq

数据结构开发:常用 len , getitem , iter

数学/科学计算库:大量使用运算符重载 (add , mul 等)。

框架/库开发:常用 call , enter , exit , getattr

相关推荐
麻雀飞吧23 分钟前
先判断工具用来学习、开发还是执行
人工智能·python
泯泷24 分钟前
那段文字是谁删的?Yjs 14 正式版之前,一套删除归属方案的实现与边界
前端·javascript·算法
hold?fish:palm32 分钟前
34 合并K个升序链表
javascript·算法·链表
人邮异步社区39 分钟前
学习Python的最佳学习路径是什么?
python·程序员
野槐3 小时前
前端项目优化(有了我,会发生...)
前端
troy1283 小时前
Python 基础语法(九):Django/Flask/FastAPI 三大 Web 框架详细对比解析
python·jupyter·django·flask·github·fastapi
jzshmyt3 小时前
我用 Python 从零“生成“了一个宇宙,然后让它观察自己(v14)
人工智能·pytorch·python·numpy·matplotlib·空间计算·scipy
幸运小圣3 小时前
PointerEvent 常用属性与事件整理【JavaScript】
开发语言·javascript·ecmascript
aa小小4 小时前
【无标题】
前端
计算机魔术师5 小时前
还在单线程跟 AI 聊天?Claude Code 并行多会话让你一个人干三个人的活
前端