Python中以双下划线开头的方法和属性(如 __init__)称为特殊方法或魔法方法(magic methods),它们的命名和使用遵循严格的约定。以下是详细分类和具体用法:
class MyClass:
def __init__(self, value): # 构造器
self.value = value
def __del__(self): # 析构器(谨慎使用)
print("对象被销毁")
obj = MyClass(10) # 触发 __init__
del obj # 触发 __del__
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)
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
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 语句 |
class Test:
def __init__(self):
self.__secret = 10 # 实际变为 _Test__secret
t = Test()
print(t._Test__secret) # 可以访问
print(t.__secret) # AttributeError
class Demo:
def __init__(self):
self.__dict__['x'] = 1 # 绕过 __setattr__
def __setattr__(self, name, value):
# 错误:self.name = value 会再次调用 __setattr__ 导致递归
# 正确:
self.__dict__[name] = value
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对象能够集成到语言基础设施中,正确使用它们可以创建出行为类似内置类型的优雅对象。