在Python中,魔术方法(Magic Methods)或称为特殊方法(Special Methods)是一系列双下划线(__
)开头和结尾的方法。这些方法在Python的类定义中扮演着特殊角色,它们为Python对象提供了丰富的内建功能,如数值运算、对象比较、属性访问控制等。掌握这些魔术方法,能够让你更深入地理解Python的对象模型,进而编写出更加灵活、强大的代码。
1. __init__(self, ...)
这是类的构造函数,用于在创建对象时初始化对象的状态。当创建类的新实例时,__init__
方法会自动被调用。
class MyClass:
def __init__(self, value):
self.value = value
obj = MyClass(10)
print(obj.value) # 输出: 10
2. __new__(cls, ...)
__new__
是一个静态方法,用于创建类的实例。在创建对象时,__new__
方法首先被调用,然后才是 __init__
方法。__new__
必须返回一个类的实例,否则将引发 TypeError
。
class Singleton:
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super().__new__(cls)
return cls._instance
def __init__(self):
pass
# 测试单例模式
obj1 = Singleton()
obj2 = Singleton()
print(obj1 is obj2) # 输出: True
3. __del__(self)
析构函数,当对象被销毁时自动调用。用于执行清理操作,如关闭文件、释放资源等。
class Resource:
def __init__(self, name):
self.name = name
print(f"{name} created")
def __del__(self):
print(f"{self.name} destroyed")
# 当Resource对象超出作用域或被显式删除时,__del__ 会被调用
r = Resource("Resource1")
del r # 输出: Resource1 destroyed
1. __getattr__(self, name)
当尝试访问一个不存在的属性时,Python会调用此方法。可以用来实现动态属性或懒加载等特性。
class LazyProperty:
def __init__(self, func):
self.func = func
def __get__(self, instance, cls):
if instance is None:
return self
result = self.func(instance)
setattr(instance, self.func.__name__, result) # 将结果缓存为实例属性
return result
class MyClass:
@LazyProperty
def expensive_calculation(self):
print("Calculating...")
return 42
obj = MyClass()
print(obj.expensive_calculation) # 第一次调用,执行计算
print(obj.expensive_calculation) # 第二次调用,从缓存中获取
2. __setattr__(self, name, value)
用于设置对象的属性值。重写此方法时,应小心避免无限递归,通常通过调用 super().__setattr__(name, value)
来处理普通属性的设置。
3. __getattribute__(self, name)
用于获取对象的属性值。与 __getattr__
不同,__getattribute__
会在任何属性访问时被调用,包括普通属性和特殊方法。因此,重写此方法时需要特别小心,以避免无限递归。
1. 序列类型
__len__(self)
:返回容器中的元素数量。__getitem__(self, key)
:根据索引或键获取容器中的元素。__setitem__(self, key, value)
:设置容器中指定索引或键的元素值。__delitem__(self, key)
:删除容器中指定索引或键的元素。2. 迭代器与生成器
__iter__(self)
:返回一个迭代器对象。__next__(self)
:返回容器的下一个元素,并在末尾引发 StopIteration
异常。示例:实现一个简单的栈
class Stack:
def __init__(self):
self.items = []
def __len__(self):
return len(self.items)
def __getitem__(self, index):
return self.items[index]
def push(self, item):
self.items.append(item)
def pop(self):
return self.items.pop()
def __iter__(self):
return iter(self.items[::-1]) # 返回逆序迭代器
# 使用栈
s = Stack()
s.push(1)
s.push(2)
s.push(3)
print(s[0]) # 输出: 3
for item in s:
print(item) # 输出: 3, 2, 1
Python中的数值类型(如整数、浮点数)支持丰富的运算符,如加法(+
)、减法(-
)等。通过定义特定的魔术方法,可以让自定义的类也支持这些运算。
__add__(self, other)
:加法。__sub__(self, other)
:减法。__mul__(self, other)
:乘法。__truediv__(self, other)
:真除法。__floordiv__(self, other)
:整数除法(地板除)。__mod__(self, other)
:取模。__pow__(self, other[, modulo])
:幂运算。示例:实现一个简单的二维向量类
class Vector2D:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __add__(self, other):
return Vector2D(self.x + other.x, self.y + other.y)
def __mul__(self, scalar):
return Vector2D(self.x * scalar, self.y * scalar)
def __str__(self):
return f"Vector2D({self.x}, {self.y})"
# 使用Vector2D
v1 = Vector2D(1, 2)
v2 = Vector2D(3, 4)
print(v1 + v2) # 输出: Vector2D(4, 6)
print(v1 * 2) # 输出: Vector2D(2, 4)
__eq__(self, other)
:等于。__ne__(self, other)
:不等于。__lt__(self, other)
:小于。__le__(self, other)
:小于等于。__gt__(self, other)
:大于。__ge__(self, other)
:大于等于。这些魔术方法定义了对象之间的比较行为,使得自定义对象可以像内置类型一样被比较和排序。
Python的魔术方法是Python对象模型的核心部分,它们为Python对象提供了丰富的行为和特性。通过定义和重写这些魔术方法,可以使得自定义的类更加灵活、强大,更加符合Python的编程习惯。然而,在重写这些魔术方法时,也需要特别注意避免无限递归、保持方法的通用性和一致性等问题。希望本章的内容能够帮助你更好地理解Python的魔术方法,并在实际编程中灵活运用它们。