> ## Content Index
> Fetch the complete content index at: https://blog.vercanti.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# 魔术方法完全参考
- URL: https://blog.vercanti.com/mo-zhu-fang-fa-wan-quan-can-kao/
- Published: 2026-08-28T14:34:37.000Z
- Updated: 2026-08-28T14:56:59.000Z
- Description: 魔术方法（Magic Methods），也称双下方法（Dunder Methods），是 Python 中以双下划线开头和结尾的特殊方法。Python 解释器在特定操作时自动调用这些方法，通过实现它们可以让自定义类与 Python 的内置语法和协议无缝集成。 创建实例时最先调用的静态方法，负责分配内存并返回新实例。 返回值：返回新创建的实例（通常是 cls 的实例）。若不返回 cls 的实例，则不会调用 __init__。 触发时机：调用 MyClass(...) 时，在 __init__ 之前调用。 实例初始化方法，负责设置实例属性。 返回值：必须返回
- Author: yellowdog
- Tags: Python, 基础

> 官方文档：<https://docs.python.org/3/reference/datamodel.html>  
> 适用版本：Python 3.12（2026-05-08 核实）

魔术方法（Magic Methods），也称双下方法（Dunder Methods），是 Python 中以双下划线开头和结尾的特殊方法。Python 解释器在特定操作时自动调用这些方法，通过实现它们可以让自定义类与 Python 的内置语法和协议无缝集成。

---

## 对象生命周期

### `__new__`

创建实例时最先调用的静态方法，负责分配内存并返回新实例。

| 参数         | 类型   | 说明                     |
| ---------- | ---- | ---------------------- |
| cls        | type | 要创建实例的类                |
| \*args     | any  | 传给 \_\_init\_\_ 的位置参数  |
| \*\*kwargs | any  | 传给 \_\_init\_\_ 的关键字参数 |

**返回值**：返回新创建的实例（通常是 `cls` 的实例）。若不返回 `cls` 的实例，则不会调用 `__init__`。

**触发时机**：调用 `MyClass(...)` 时，在 `__init__` 之前调用。

```python
class Singleton:
    _instance = None

    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance

    def __init__(self, value):
        self.value = value

a = Singleton(1)
b = Singleton(2)
print(a is b)     # True
print(a.value)    # 2（__init__ 被调用了两次）

# 不可变类型的子类化必须在 __new__ 中修改值
class UpperStr(str):
    def __new__(cls, value):
        return super().__new__(cls, value.upper())

s = UpperStr('hello')
print(s)  # 'HELLO'

```

---

### `__init__`

实例初始化方法，负责设置实例属性。

| 参数         | 类型       | 说明                   |
| ---------- | -------- | -------------------- |
| self       | instance | 已由 \_\_new\_\_ 创建的实例 |
| \*args     | any      | 构造函数的位置参数            |
| \*\*kwargs | any      | 构造函数的关键字参数           |

**返回值**：必须返回 `None`，否则抛出 `TypeError`。

**触发时机**：`__new__` 返回 `cls` 实例后立即调用。

```python
class Point:
    def __init__(self, x: float, y: float):
        self.x = x
        self.y = y

p = Point(1.0, 2.0)

```

---

### `__del__`

对象被垃圾回收时调用，也称析构方法。

| 参数   | 类型       | 说明       |
| ---- | -------- | -------- |
| self | instance | 即将被销毁的实例 |

**返回值**：无。

**触发时机**：对象引用计数降为 0 时（CPython）。注意：时机不确定，程序退出时可能不被调用。

```python
class Resource:
    def __init__(self, name):
        self.name = name
        print(f"Acquired: {self.name}")

    def __del__(self):
        print(f"Released: {self.name}")

r = Resource("file_handle")
del r  # 打印 "Released: file_handle"

# 注意：不要依赖 __del__ 释放关键资源，应使用上下文管理器

```

---

### `__init_subclass__`

当该类被继承时调用，可用于自动注册子类或强制接口约束。

| 参数         | 类型   | 说明          |
| ---------- | ---- | ----------- |
| cls        | type | 新创建的子类      |
| \*\*kwargs | any  | 传给该方法的关键字参数 |

**返回值**：无。

**触发时机**：定义子类时（类创建阶段），而非实例化时。

```python
class Plugin:
    _registry = {}

    def __init_subclass__(cls, plugin_name=None, **kwargs):
        super().__init_subclass__(**kwargs)
        if plugin_name:
            Plugin._registry[plugin_name] = cls
            print(f"Registered plugin: {plugin_name}")

class AuthPlugin(Plugin, plugin_name='auth'):
    pass

class LogPlugin(Plugin, plugin_name='log'):
    pass

print(Plugin._registry)
# {'auth': <class 'AuthPlugin'>, 'log': <class 'LogPlugin'>}

```

---

## 字符串表示

### `__repr__`

返回对象的"官方"字符串表示，目标是能通过 `eval()` 重新构造对象（尽力而为）。

| 参数   | 类型       | 说明   |
| ---- | -------- | ---- |
| self | instance | 当前实例 |

**返回值**：`str`。

**触发时机**：`repr(obj)`、交互式解释器显示、`f"{obj!r}"`、容器打印时对元素调用。

```python
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __repr__(self):
        return f"Point({self.x!r}, {self.y!r})"

p = Point(1, 2)
print(repr(p))   # Point(1, 2)
print([p])       # [Point(1, 2)]（列表打印元素时用 repr）

```

---

### `__str__`

返回对象的可读字符串表示，面向用户展示。

| 参数   | 类型       | 说明   |
| ---- | -------- | ---- |
| self | instance | 当前实例 |

**返回值**：`str`。

**触发时机**：`str(obj)`、`print(obj)`、`f"{obj}"`、`f"{obj!s}"`。未定义时回退到 `__repr__`。

```python
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __repr__(self):
        return f"Point({self.x!r}, {self.y!r})"

    def __str__(self):
        return f"({self.x}, {self.y})"

p = Point(1, 2)
print(str(p))    # (1, 2)
print(repr(p))   # Point(1, 2)

```

---

### `__format__`

支持 `format()` 内置函数和 f-string 的格式规范。

| 参数           | 类型       | 说明                                |
| ------------ | -------- | --------------------------------- |
| self         | instance | 当前实例                              |
| format\_spec | str      | 格式规范字符串（如 .2f、\>10 等），空字符串表示无格式要求 |

**返回值**：`str`。

**触发时机**：`format(obj, spec)`、`f"{obj:spec}"`。

```python
class Money:
    def __init__(self, amount, currency='CNY'):
        self.amount = amount
        self.currency = currency

    def __format__(self, spec):
        if spec == 'short':
            return f"{self.amount:.0f}"
        elif spec == 'full':
            return f"{self.currency} {self.amount:,.2f}"
        return f"{self.amount:{spec}}" if spec else str(self.amount)

m = Money(1234.5)
print(f"{m:full}")   # CNY 1,234.50
print(f"{m:short}")  # 1235
print(f"{m:.2f}")    # 1234.50

```

---

### `__bytes__`

返回对象的字节串表示。

| 参数   | 类型       | 说明   |
| ---- | -------- | ---- |
| self | instance | 当前实例 |

**返回值**：`bytes`。

**触发时机**：`bytes(obj)`。

```python
class Packet:
    def __init__(self, data: str):
        self.data = data

    def __bytes__(self):
        return self.data.encode('utf-8')

p = Packet('hello')
print(bytes(p))  # b'hello'

```

---

## 比较运算

### 比较方法总览

| 方法                      | 运算符 | 触发时机                        |
| ----------------------- | --- | --------------------------- |
| \_\_eq\_\_(self, other) | \== | a == b                      |
| \_\_ne\_\_(self, other) | !=  | a != b（未定义时默认取反 \_\_eq\_\_） |
| \_\_lt\_\_(self, other) | <   | a < b                       |
| \_\_le\_\_(self, other) | <=  | a <= b                      |
| \_\_gt\_\_(self, other) | \>  | a > b                       |
| \_\_ge\_\_(self, other) | \>= | a >= b                      |

每个比较方法的参数：

| 参数    | 类型       | 说明      |
| ----- | -------- | ------- |
| self  | instance | 运算符左侧对象 |
| other | any      | 运算符右侧对象 |

**返回值**：通常返回 `bool`，但可以返回任意值（NumPy 返回数组）。当无法与 `other` 比较时应返回 `NotImplemented`（不是 `NotImplementedError`），Python 会尝试调用 `other` 的反射方法。

```python
from functools import total_ordering

@total_ordering
class Version:
    def __init__(self, major, minor, patch):
        self.major = major
        self.minor = minor
        self.patch = patch

    def _tuple(self):
        return (self.major, self.minor, self.patch)

    def __eq__(self, other):
        if not isinstance(other, Version):
            return NotImplemented
        return self._tuple() == other._tuple()

    def __lt__(self, other):
        if not isinstance(other, Version):
            return NotImplemented
        return self._tuple() < other._tuple()

    def __repr__(self):
        return f"Version({self.major}, {self.minor}, {self.patch})"

v1 = Version(1, 2, 0)
v2 = Version(1, 3, 0)
print(v1 < v2)   # True
print(v1 > v2)   # False（total_ordering 自动生成）
print(sorted([v2, v1]))  # [Version(1, 2, 0), Version(1, 3, 0)]

```

---

### `__hash__`

返回对象的哈希值，使对象可用于集合或字典键。

| 参数   | 类型       | 说明   |
| ---- | -------- | ---- |
| self | instance | 当前实例 |

**返回值**：`int`。

**触发时机**：`hash(obj)`、将对象放入 `set` 或用作 `dict` 键。

```python
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __eq__(self, other):
        return isinstance(other, Point) and self.x == other.x and self.y == other.y

    def __hash__(self):
        # 基于值的哈希，与 __eq__ 保持一致
        return hash((self.x, self.y))

p1 = Point(1, 2)
p2 = Point(1, 2)
print(p1 == p2)   # True
print(hash(p1) == hash(p2))  # True
print({p1, p2})   # {Point(1, 2)}（只有一个元素）

```

**重要陷阱**：定义 `__eq__` 后，Python 自动将 `__hash__` 设为 `None`，使对象不可哈希。若要对象同时支持相等比较和哈希，必须显式定义 `__hash__`。

```python
class BadPoint:
    def __eq__(self, other):
        return True  # 定义了 __eq__ 但没定义 __hash__

p = BadPoint()
hash(p)  # TypeError: unhashable type: 'BadPoint'

```

---

## 数值运算

### 二元运算符

| 方法                            | 运算符  | 说明   |
| ----------------------------- | ---- | ---- |
| \_\_add\_\_(self, other)      | +    | 加法   |
| \_\_sub\_\_(self, other)      | \-   | 减法   |
| \_\_mul\_\_(self, other)      | \*   | 乘法   |
| \_\_truediv\_\_(self, other)  | /    | 真除法  |
| \_\_floordiv\_\_(self, other) | //   | 整除   |
| \_\_mod\_\_(self, other)      | %    | 取模   |
| \_\_pow\_\_(self, other)      | \*\* | 幂运算  |
| \_\_matmul\_\_(self, other)   | @    | 矩阵乘法 |

每个方法参数相同：

| 参数    | 类型       | 说明   |
| ----- | -------- | ---- |
| self  | instance | 左操作数 |
| other | any      | 右操作数 |

**返回值**：运算结果，无法处理时返回 `NotImplemented`。

### 反射运算符（右操作数版本）

当左操作数不支持该运算时，Python 尝试调用右操作数的反射版本：

| 方法                             | 对应正向方法           |
| ------------------------------ | ---------------- |
| \_\_radd\_\_(self, other)      | \_\_add\_\_      |
| \_\_rsub\_\_(self, other)      | \_\_sub\_\_      |
| \_\_rmul\_\_(self, other)      | \_\_mul\_\_      |
| \_\_rtruediv\_\_(self, other)  | \_\_truediv\_\_  |
| \_\_rfloordiv\_\_(self, other) | \_\_floordiv\_\_ |
| \_\_rmod\_\_(self, other)      | \_\_mod\_\_      |
| \_\_rpow\_\_(self, other)      | \_\_pow\_\_      |

### 原地运算符

| 方法                        | 运算符 | 说明   |
| ------------------------- | --- | ---- |
| \_\_iadd\_\_(self, other) | +=  | 原地加法 |
| \_\_isub\_\_(self, other) | \-= | 原地减法 |
| \_\_imul\_\_(self, other) | \*= | 原地乘法 |

```python
class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __add__(self, other):
        if isinstance(other, Vector):
            return Vector(self.x + other.x, self.y + other.y)
        return NotImplemented

    def __radd__(self, other):
        # 支持 0 + Vector（sum() 从 0 开始累加时需要此方法）
        if other == 0:
            return self
        return NotImplemented

    def __mul__(self, scalar):
        if isinstance(scalar, (int, float)):
            return Vector(self.x * scalar, self.y * scalar)
        return NotImplemented

    def __rmul__(self, scalar):
        return self.__mul__(scalar)

    def __iadd__(self, other):
        if isinstance(other, Vector):
            self.x += other.x
            self.y += other.y
            return self  # 原地修改，返回 self
        return NotImplemented

    def __neg__(self):
        return Vector(-self.x, -self.y)

    def __abs__(self):
        import math
        return math.sqrt(self.x**2 + self.y**2)

    def __repr__(self):
        return f"Vector({self.x}, {self.y})"

v1 = Vector(1, 2)
v2 = Vector(3, 4)

print(v1 + v2)      # Vector(4, 6)
print(v1 * 3)       # Vector(3, 6)
print(3 * v1)       # Vector(3, 6)（通过 __rmul__）
print(-v1)          # Vector(-1, -2)
print(abs(v2))      # 5.0
print(sum([v1, v2]))  # Vector(4, 6)（sum 从 0 开始，触发 __radd__）

v1 += v2
print(v1)  # Vector(4, 6)

```

### 一元运算符

| 方法                   | 运算符      | 说明   | 返回值 |
| -------------------- | -------- | ---- | --- |
| \_\_neg\_\_(self)    | \-obj    | 取负   | 新对象 |
| \_\_pos\_\_(self)    | +obj     | 取正   | 新对象 |
| \_\_abs\_\_(self)    | abs(obj) | 绝对值  | 数值  |
| \_\_invert\_\_(self) | \~obj    | 按位取反 | 整数  |

---

## 容器协议

### `__len__`

返回容器的元素数量。

| 参数   | 类型       | 说明   |
| ---- | -------- | ---- |
| self | instance | 当前实例 |

**返回值**：非负整数。

**触发时机**：`len(obj)`，也被 `bool(obj)` 用于真值判断（若未定义 `__bool__`）。

---

### `__getitem__`、`__setitem__`、`__delitem__`

实现下标访问、赋值和删除。

| 参数                       | 类型       | 说明                 |
| ------------------------ | -------- | ------------------ |
| self                     | instance | 当前实例               |
| key                      | any      | 索引或键，可以是整数、切片、字符串等 |
| value（仅 \_\_setitem\_\_） | any      | 要设置的值              |

**触发时机**：`obj[key]`、`obj[key] = value`、`del obj[key]`。

---

### `__contains__`

实现 `in` 运算符。

| 参数   | 类型       | 说明     |
| ---- | -------- | ------ |
| self | instance | 当前实例   |
| item | any      | 要查找的元素 |

**返回值**：`bool`。未定义时 Python 会遍历迭代器逐一比较。

---

### `__iter__` 和 `__next__`

实现迭代器协议。

| 方法                 | 参数   | 返回值      | 说明                        |
| ------------------ | ---- | -------- | ------------------------- |
| \_\_iter\_\_(self) | self | iterator | 返回迭代器对象（通常返回 self）        |
| \_\_next\_\_(self) | self | any      | 返回下一个值，耗尽时抛 StopIteration |

**触发时机**：`iter(obj)` 触发 `__iter__`，`next(obj)` 触发 `__next__`，`for` 循环自动调用两者。

---

### `__reversed__`

支持 `reversed()` 内置函数。

| 参数   | 类型       | 说明   |
| ---- | -------- | ---- |
| self | instance | 当前实例 |

**返回值**：逆序迭代器。

```python
class Playlist:
    def __init__(self, songs):
        self._songs = list(songs)

    def __len__(self):
        return len(self._songs)

    def __getitem__(self, index):
        return self._songs[index]

    def __setitem__(self, index, value):
        self._songs[index] = value

    def __delitem__(self, index):
        del self._songs[index]

    def __contains__(self, song):
        return song in self._songs

    def __iter__(self):
        return iter(self._songs)

    def __reversed__(self):
        return reversed(self._songs)

    def __repr__(self):
        return f"Playlist({self._songs!r})"

pl = Playlist(['A', 'B', 'C'])
print(len(pl))           # 3
print(pl[0])             # 'A'
print('B' in pl)         # True
print(list(reversed(pl)))  # ['C', 'B', 'A']

for song in pl:
    print(song)          # A, B, C

```

---

## 属性访问

### `__getattr__`

仅在正常属性查找失败时调用（属性不存在时的兜底方法）。

| 参数   | 类型       | 说明   |
| ---- | -------- | ---- |
| self | instance | 当前实例 |
| name | str      | 属性名  |

**返回值**：属性值，或抛出 `AttributeError`。

**触发时机**：访问不存在的属性时。不会拦截已存在属性的访问。

---

### `__getattribute__`

拦截所有属性访问，包括已存在的属性。

| 参数   | 类型       | 说明   |
| ---- | -------- | ---- |
| self | instance | 当前实例 |
| name | str      | 属性名  |

**返回值**：属性值，或抛出 `AttributeError`。

**触发时机**：任何属性访问都会触发，包括 `self.x`。

---

### `__setattr__`、`__delattr__`

拦截属性赋值和删除。

| 参数                       | 类型       | 说明    |
| ------------------------ | -------- | ----- |
| self                     | instance | 当前实例  |
| name                     | str      | 属性名   |
| value（仅 \_\_setattr\_\_） | any      | 要设置的值 |

**触发时机**：`obj.attr = value`、`del obj.attr`。

---

### `__dir__`

自定义 `dir()` 的返回值。

| 参数   | 类型       | 说明   |
| ---- | -------- | ---- |
| self | instance | 当前实例 |

**返回值**：属性名列表（可迭代对象）。

```python
class DynamicProxy:
    def __init__(self, target):
        object.__setattr__(self, '_target', target)

    def __getattr__(self, name):
        # 只在属性不存在时调用，代理到目标对象
        return getattr(self._target, name)

    def __getattribute__(self, name):
        # 拦截所有访问
        if name.startswith('_'):
            return object.__getattribute__(self, name)
        print(f"Accessing: {name}")
        return object.__getattribute__(self, name)

    def __setattr__(self, name, value):
        if name.startswith('_'):
            object.__setattr__(self, name, value)
        else:
            print(f"Setting: {name} = {value}")
            object.__setattr__(self, name, value)

    def __dir__(self):
        base = list(object.__dir__(self))
        target_attrs = dir(self._target)
        return sorted(set(base + target_attrs))

# 关键：在 __getattribute__ 和 __setattr__ 中必须用 object.__xxx__ 访问自身属性
# 否则会导致无限递归

```

**`__getattr__` vs `__getattribute__` 的核心区别**：

| 特性     | \_\_getattr\_\_ | \_\_getattribute\_\_                   |
| ------ | --------------- | -------------------------------------- |
| 触发条件   | 属性不存在时          | 所有属性访问                                 |
| 用途     | 动态属性、代理         | 全面拦截、访问控制                              |
| 无限递归风险 | 低               | 高（内部访问必须用 object.\_\_getattribute\_\_） |
| 性能开销   | 低（仅失败时触发）       | 高（每次访问都触发）                             |

---

## 描述符

描述符是定义了 `__get__`、`__set__` 或 `__delete__` 的对象，通过类属性的方式管理实例属性。

### `__get__`

| 参数      | 类型              | 说明                     |
| ------- | --------------- | ---------------------- |
| self    | descriptor      | 描述符实例                  |
| obj     | instance / None | 访问该描述符的实例，通过类访问时为 None |
| objtype | type            | 实例的类（或直接访问的类）          |

**返回值**：属性值。

### `__set__`

| 参数    | 类型         | 说明       |
| ----- | ---------- | -------- |
| self  | descriptor | 描述符实例    |
| obj   | instance   | 属性被设置的实例 |
| value | any        | 要设置的值    |

**返回值**：无（None）。

### `__delete__`

| 参数   | 类型         | 说明       |
| ---- | ---------- | -------- |
| self | descriptor | 描述符实例    |
| obj  | instance   | 属性被删除的实例 |

**返回值**：无（None）。

### `__set_name__`

类创建时调用，告知描述符其在类中的属性名。

| 参数    | 类型         | 说明         |
| ----- | ---------- | ---------- |
| self  | descriptor | 描述符实例      |
| owner | type       | 拥有该描述符的类   |
| name  | str        | 描述符在类中的属性名 |

```python
class Validator:
    """带类型验证的描述符"""

    def __set_name__(self, owner, name):
        self.name = name
        self.private_name = f'_{name}'

    def __get__(self, obj, objtype=None):
        if obj is None:
            return self  # 通过类访问时返回描述符本身
        return getattr(obj, self.private_name, None)

    def __set__(self, obj, value):
        self.validate(value)
        setattr(obj, self.private_name, value)

    def validate(self, value):
        pass  # 子类实现

class PositiveInt(Validator):
    def validate(self, value):
        if not isinstance(value, int) or value <= 0:
            raise ValueError(f"{self.name} must be a positive integer, got {value!r}")

class Person:
    age = PositiveInt()

    def __init__(self, name, age):
        self.name = name
        self.age = age  # 触发 PositiveInt.__set__

p = Person('Alice', 30)
print(p.age)   # 30

try:
    p.age = -1  # ValueError: age must be a positive integer, got -1
except ValueError as e:
    print(e)

# 通过类访问返回描述符本身
print(Person.age)  # <__main__.PositiveInt object at ...>

```

**描述符分类**：

| 类型     | 条件                               | 说明                   |
| ------ | -------------------------------- | -------------------- |
| 数据描述符  | 定义了 \_\_set\_\_ 或 \_\_delete\_\_ | 优先级高于实例 \_\_dict\_\_ |
| 非数据描述符 | 只定义了 \_\_get\_\_                 | 优先级低于实例 \_\_dict\_\_ |

---

## 上下文管理器

### `__enter__` 和 `__exit__`

实现 `with` 语句协议。

`__enter__` 参数：

| 参数   | 类型       | 说明       |
| ---- | -------- | -------- |
| self | instance | 上下文管理器实例 |

**返回值**：绑定到 `as` 子句变量的值（无 `as` 时不使用）。

`__exit__` 参数：

| 参数        | 类型               | 说明                          |
| --------- | ---------------- | --------------------------- |
| self      | instance         | 上下文管理器实例                    |
| exc\_type | type / None      | 异常类型，无异常时为 None             |
| exc\_val  | Exception / None | 异常实例，无异常时为 None             |
| exc\_tb   | traceback / None | 异常的 traceback 对象，无异常时为 None |

**返回值**：真值表示吞掉（抑制）异常；假值（或 None）表示继续传播异常。

```python
import time

class Timer:
    def __enter__(self):
        self.start = time.perf_counter()
        return self  # as 子句拿到 self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.elapsed = time.perf_counter() - self.start
        if exc_type is not None:
            print(f"Exception occurred after {self.elapsed:.4f}s: {exc_val}")
        else:
            print(f"Elapsed: {self.elapsed:.4f}s")
        return False  # 不抑制异常

with Timer() as t:
    total = sum(range(1_000_000))

print(f"Sum: {total}, Time: {t.elapsed:.4f}s")

# 抑制特定异常
class SuppressZeroDivision:
    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        return exc_type is ZeroDivisionError  # 只抑制 ZeroDivisionError

with SuppressZeroDivision():
    result = 1 / 0  # 不会抛出异常
print("Continued normally")

```

---

## 可调用对象

### `__call__`

使实例可像函数一样被调用。

| 参数         | 类型       | 说明          |
| ---------- | -------- | ----------- |
| self       | instance | 当前实例        |
| \*args     | any      | 调用时传入的位置参数  |
| \*\*kwargs | any      | 调用时传入的关键字参数 |

**返回值**：任意值。

**触发时机**：`obj(...)`。

```python
class Multiplier:
    def __init__(self, factor):
        self.factor = factor

    def __call__(self, x):
        return x * self.factor

double = Multiplier(2)
triple = Multiplier(3)

print(double(5))   # 10
print(triple(5))   # 15

# 可调用对象与函数的区别：可以携带状态
class Counter:
    def __init__(self):
        self.count = 0

    def __call__(self, *args, **kwargs):
        self.count += 1
        return self.count

c = Counter()
print(c())  # 1
print(c())  # 2
print(c.count)  # 2

# 检测可调用性
print(callable(double))   # True
print(callable(42))       # False

```

---

## 类型系统

### `__class_getitem__`

支持泛型类型参数语法 `MyClass[type]`。

| 参数   | 类型   | 说明        |
| ---- | ---- | --------- |
| cls  | type | 类本身       |
| item | any  | 方括号内的类型参数 |

**返回值**：通常返回 `types.GenericAlias` 或自定义对象。

**触发时机**：`MyClass[int]`、`MyClass[str, int]`。

```python
class Stack:
    def __class_getitem__(cls, item):
        return f"Stack[{item.__name__}]"

print(Stack[int])   # Stack[int]
print(Stack[str])   # Stack[str]

# 实际用于类型注解
from typing import Generic, TypeVar
T = TypeVar('T')

class TypedStack(Generic[T]):
    def __init__(self):
        self._data: list[T] = []

    def push(self, item: T) -> None:
        self._data.append(item)

    def pop(self) -> T:
        return self._data.pop()

stack: TypedStack[int] = TypedStack()

```

---

### `__instancecheck__` 和 `__subclasscheck__`

自定义 `isinstance()` 和 `issubclass()` 的行为，定义在**元类**上。

| 方法                                   | 参数                      | 触发时机                      |
| ------------------------------------ | ----------------------- | ------------------------- |
| \_\_instancecheck\_\_(cls, instance) | cls: 类, instance: 待检测对象 | isinstance(instance, cls) |
| \_\_subclasscheck\_\_(cls, subclass) | cls: 类, subclass: 待检测类  | issubclass(subclass, cls) |

```python
class SupportsAddMeta(type):
    def __instancecheck__(cls, instance):
        return hasattr(instance, '__add__')

    def __subclasscheck__(cls, subclass):
        return hasattr(subclass, '__add__')

class SupportsAdd(metaclass=SupportsAddMeta):
    pass

print(isinstance(1, SupportsAdd))      # True（int 有 __add__）
print(isinstance('a', SupportsAdd))    # True（str 有 __add__）
print(isinstance(None, SupportsAdd))   # False（None 没有 __add__）

```

---

## 序列化

### `__getstate__` 和 `__setstate__`

自定义对象的序列化和反序列化行为，用于 `pickle`。

`__getstate__` 参数：

| 参数   | 类型       | 说明   |
| ---- | -------- | ---- |
| self | instance | 当前实例 |

**返回值**：任意可序列化对象（通常是字典），表示对象状态。

`__setstate__` 参数：

| 参数    | 类型       | 说明                    |
| ----- | -------- | --------------------- |
| self  | instance | 当前实例（尚未初始化）           |
| state | any      | \_\_getstate\_\_ 的返回值 |

**返回值**：无。

```python
import pickle

class Connection:
    def __init__(self, host, port):
        self.host = host
        self.port = port
        self._socket = None  # 不可序列化的资源

    def connect(self):
        self._socket = f"<socket to {self.host}:{self.port}>"

    def __getstate__(self):
        # 不序列化 socket 连接
        state = self.__dict__.copy()
        state['_socket'] = None
        return state

    def __setstate__(self, state):
        self.__dict__.update(state)
        # 反序列化后不自动重连

conn = Connection('localhost', 5432)
conn.connect()
print(conn._socket)   # <socket to localhost:5432>

serialized = pickle.dumps(conn)
restored = pickle.loads(serialized)
print(restored._socket)  # None（socket 未被序列化）
print(restored.host)     # 'localhost'

```

---

### `__reduce__`

提供完整的序列化控制，返回重建对象所需的信息。

| 参数   | 类型       | 说明   |
| ---- | -------- | ---- |
| self | instance | 当前实例 |

**返回值**：元组 `(callable, args)` 或 `(callable, args, state, ...)`，callable(\*args) 用于重建对象。

```python
class MyObj:
    def __init__(self, data):
        self.data = data

    def __reduce__(self):
        return (self.__class__, (self.data,))

```

---

## 踩坑与注意事项

### 1\. `__eq__` 重写后 `__hash__` 自动变 None

```python
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __eq__(self, other):
        return (self.x, self.y) == (other.x, other.y)
    # 没有定义 __hash__！

p = Point(1, 2)
hash(p)  # TypeError: unhashable type: 'Point'

{p: 'origin'}  # TypeError: unhashable type: 'Point'

# 修复：显式定义 __hash__
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __eq__(self, other):
        return (self.x, self.y) == (other.x, other.y)

    def __hash__(self):
        return hash((self.x, self.y))

# 若要声明对象不可哈希（可变对象的最佳实践）：
# __hash__ = None

```

### 2\. `__getattr__` 与 `__getattribute__` 的无限递归

```python
class BadProxy:
    def __getattribute__(self, name):
        # 错误：self.data 会再次触发 __getattribute__，导致无限递归
        return self.data[name]  # RecursionError!

class GoodProxy:
    def __getattribute__(self, name):
        # 正确：使用 object.__getattribute__ 访问自身属性
        data = object.__getattribute__(self, 'data')
        return data[name]

```

### 3\. `__del__` 的不确定性

```python
class Resource:
    def __del__(self):
        # 不要在这里做关键清理
        # 1. 循环引用时可能不被调用
        # 2. 程序崩溃时不被调用
        # 3. 解释器退出时调用顺序不确定
        pass

# 正确做法：使用上下文管理器
class Resource:
    def __enter__(self):
        return self

    def __exit__(self, *args):
        self.cleanup()  # 确保被调用

```

### 4\. `__exit__` 返回值容易搞错

```python
class BadContextManager:
    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        # 错误：无论是否有异常，总是返回 True，会吞掉所有异常
        return True

class GoodContextManager:
    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        if exc_type is ValueError:
            print(f"Suppressed ValueError: {exc_val}")
            return True   # 仅抑制 ValueError
        return False      # 其他异常正常传播

```

### 5\. `__new__` 返回不同类型时不调用 `__init__`

```python
class MyClass:
    def __new__(cls, value):
        if value < 0:
            return None  # 返回非 cls 实例
        return super().__new__(cls)

    def __init__(self, value):
        print("__init__ called")  # 当 value < 0 时不会执行
        self.value = value

obj = MyClass(-1)
print(obj)   # None，__init__ 未被调用

```

### 6\. 描述符只对类属性有效

```python
class MyDescriptor:
    def __get__(self, obj, objtype=None):
        return 42

class MyClass:
    attr = MyDescriptor()  # 类属性，描述符生效

obj = MyClass()
print(obj.attr)         # 42（通过描述符）

obj.__dict__['attr'] = 100  # 直接写入实例字典
# 数据描述符（有 __set__）：obj.attr 仍返回 42（描述符优先）
# 非数据描述符（无 __set__）：obj.attr 返回 100（实例字典优先）

```

---

## 最佳实践

**实现 `__eq__` 必须同时实现 `__hash__`**：Python 3 中定义 `__eq__` 后，`__hash__` 会被自动设为 `None`（对象变为不可哈希），无法作为 dict key 或 set 元素。可变对象显式设 `__hash__ = None`，不可变对象同时实现两者并保证 hash 一致性。

**`__repr__` 应返回可重现对象的字符串**：理想格式是 `ClassName(arg1=val1, arg2=val2)`，能被 `eval()` 重新创建对象；至少要包含足够信息让开发者调试定位问题。

**用 `__slots__` 减少内存占用**：大量实例时，`__slots__` 替代 `__dict__` 存储实例属性，内存节省 20-50%；但 `__slots__` 不支持默认实例属性，需要在 `__init__` 中初始化所有槽。

**`__enter__` / `__exit__` 成对实现**：只要类实现这两个方法，就能用于 `with` 语句，无需继承任何基类；`__exit__` 返回 `True` 时抑制异常，通常应返回 `None` / `False`。

**谨慎使用 `__getattr__` vs `__getattribute__`**：`__getattr__` 只在属性查找失败时调用（安全），`__getattribute__` 在任何属性访问时调用（容易无限递归）；在 `__getattribute__` 中访问 `self` 属性必须用 `object.__getattribute__(self, name)`。

---

## 常见陷阱

### 陷阱：`__del__` 不等于析构函数，不可靠

**现象：** 期望 `__del__` 在对象销毁时释放资源，但资源没有被及时释放，或程序退出时才执行。  
**原因：** `__del__` 依赖 CPython 的引用计数，存在循环引用时无法预测调用时机，解释器退出时调用顺序也不确定。  
**解决：** 资源管理用上下文管理器（`with`）和 `__enter__`/`__exit__`，或显式调用 `close()` 方法。

### 陷阱：`__init_subclass__` 替代元类

**现象：** 用元类（metaclass）拦截子类定义时代码复杂难维护。  
**原因：** 很多元类使用场景可以用 Python 3.6+ 的 `__init_subclass__` 实现，更简洁。  
**解决：** 当需要在子类定义时执行逻辑时，优先考虑 `__init_subclass__`，只有需要拦截 `type()` 调用本身时才用元类。

### 陷阱：`__iadd__` 返回值决定变量是否重绑定

**现象：** `list += [1]` 不改变变量绑定（原地修改），但 `tuple += (1,)` 创建新对象并重绑定变量。  
**原因：** `+=` 调用 `__iadd__`，若返回 `self`（如 `list`），变量不重绑定；若返回新对象（如 `tuple`），变量重绑定到新对象。  
**解决：** 实现 `__iadd__` 时原地修改并 `return self`，保持与内置 list 行为一致。

---

## 参见

[装饰器与函数高级](https://blog.vercanti.com/python-zhuang-shi-qi-yu-han-shu-gao-ji-yong-fa/)  
[itertools与functools完全指南](https://blog.vercanti.com/itertools-yu-functools-wan-quan-zhi-nan/)  
[内置函数完全参考](https://blog.vercanti.com/python-nei-zhi-han-shu-wan-quan-can-kao/)