Python中以双下划线开头的方法和属性(如 __init__)称为特殊方法或魔法方法(magic methods),它们的命名和使用遵循严格的约定。以下是详细分类和具体用法:
一、核心用途分类
1. 对象生命周期控制
class MyClass:
def __init__(self, value): # 构造器
self.value = value
def __del__(self): # 析构器(谨慎使用)
print("对象被销毁")
obj = MyClass(10) # 触发 __init__
del obj # 触发 __del__
2. 运算符重载
class Vector:
def __init__(self, x, y):
self.x, self.y = x, y
def __add__(self, other): # 重载 + 运算符
return Vector(self.x + other.x, self.y + other.y)
def __str__(self): # 重载 print()
return f"Vector({self.x}, {self.y})"
v1 = Vector(1, 2)
v2 = Vector(3, 4)
print(v1 + v2) # Vector(4, 6)
3. 容器类型模拟
class Stack:
def __init__(self):
self._items = []
def __len__(self): # 重载 len()
return len(self._items)
def __getitem__(self, index): # 重载 []
return self._items[index]
def __setitem__(self, index, value): # 支持 s[0]=x
self._items[index] = value
s = Stack()
s._items = [1, 2, 3]
print(len(s)) # 3
print(s[1]) # 2
4. 属性访问控制
class Secret:
def __init__(self):
self.public = "公开"
self._protected = "受保护"
self.__private = "私有" # 名称修饰(name mangling)
def __getattr__(self, name): # 访问不存在的属性时触发
return f"{name} 不存在"
s = Secret()
print(s.public) # "公开"
print(s._protected) # "受保护"
print(s._Secret__private) # "私有"(实际被重命名为 _Secret__private)
print(s.abc) # "abc 不存在"(触发 __getattr__)
二、常见魔法方法速查表
| 分类 |
方法 |
触发场景 |
|---|
| 构造/析构 |
__new__ |
创建实例时第一个调用 |
|
__init__ |
对象初始化 |
|
__del__ |
对象销毁 |
| 字符串表示 |
__str__ |
print(obj)、str(obj) |
|
__repr__ |
repr(obj)、交互式显示 |
| 运算符 |
__add__/__sub__ |
+/- 运算 |
|
__eq__/__lt__ |
==/< 比较 |
| 容器操作 |
__len__ |
len(obj) |
|
__getitem__ |
obj[key] |
|
__iter__ |
for x in obj |
| 属性管理 |
__getattr__ |
访问不存在的属性 |
|
__setattr__ |
设置属性时 |
|
__getattribute__ |
所有属性访问时 |
| 上下文管理 |
__enter__/__exit__ |
with 语句 |
三、重要细节
1. 名称修饰(Name Mangling)
class Test:
def __init__(self):
self.__secret = 10 # 实际变为 _Test__secret
t = Test()
print(t._Test__secret) # 可以访问
print(t.__secret) # AttributeError
2. 避免无限递归
class Demo:
def __init__(self):
self.__dict__['x'] = 1 # 绕过 __setattr__
def __setattr__(self, name, value):
# 错误:self.name = value 会再次调用 __setattr__ 导致递归
# 正确:
self.__dict__[name] = value
3. 上下文管理器示例
class FileManager:
def __init__(self, filename):
self.filename = filename
def __enter__(self):
self.file = open(self.filename, 'w')
return self.file
def __exit__(self, exc_type, exc_val, exc_tb):
self.file.close()
with FileManager("test.txt") as f:
f.write("Hello")
四、使用建议
不要随意创建自定义双下划线方法,除非需要特殊行为
优先使用公开接口,私有属性用单下划线
_var
魔法方法不是设计模式替代品,避免过度使用
阅读内置类型源码(如
collections.abc)学习标准实现
五、示例:完整类设计
class Rational:
"""有理数类示例"""
def __init__(self, numerator, denominator=1):
self.n = numerator
self.d = denominator
def __add__(self, other):
# 简化版加法
return Rational(self.n + other.n, self.d)
def __str__(self):
return f"{self.n}/{self.d}"
def __repr__(self):
return f"Rational({self.n}, {self.d})"
def __float__(self):
return self.n / self.d
r1 = Rational(1, 2)
r2 = Rational(3, 2)
print(r1 + r2) # 4/2
print(float(r1)) # 0.5
记住:双下划线方法让Python对象能够集成到语言基础设施中,正确使用它们可以创建出行为类似内置类型的优雅对象。