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

相关推荐
深蓝轨迹2 小时前
@Autowired与@Resource:Spring依赖注入注解核心差异剖析
java·python·spring·注解
人工智能AI技术2 小时前
Python 3.14.3更新!内存优化与安全补丁实战应用
python
楠木6852 小时前
从零实现一个 Vite 自动路由插件
前端
2401_891655812 小时前
此电脑网络位置异常的AD域排错指南的技术文章大纲
开发语言·python·算法
终端鹿2 小时前
Vue2 迁移 Vue3 避坑指南
前端·javascript·vue.js
不要秃头的小孩2 小时前
50. 随机数排序
数据结构·python·算法
进击的尘埃2 小时前
Signals 跨框架收敛:TC39 提案、Solid、Angular、Preact 的实现差异与调度策略对比
javascript
程序员陆业聪2 小时前
工程师的瓶颈,已经不是代码了
前端
qq_417695052 小时前
实战:用OpenCV和Python进行人脸识别
jvm·数据库·python