Python魔法方法(Magic Methods)

  Python魔法方法(Magic Methods),也称为双下划线方法或特殊方法,是Python类中以双下划线包围的特殊方法,如 __init__ 或 __str__。这些方法无需主动调用,而是在特定场景下由Python解释器自动触发,用于自定义对象的行为,使其能够与内置操作符和函数交互。‌

  ‌魔法方法的核心作用是自定义对象的内置行为。它们几乎每个都有对应的内置函数或运算符,当对对象使用这些函数或运算符时,Python会自动调用类中定义的相应魔法方法。‌
  构造与初始化魔法方法‌ 在对象创建过程中起关键作用,主要包括:

  __new__:在对象创建时第一个被调用,负责‌创建并返回类的实例‌,它是静态方法,必须返回一个实例,否则 __init__ 不会被触发。
  __init__:在实例创建后自动调用,用于‌初始化实例属性‌,例如设置初始值。
  __del__:在对象生命周期结束时调用,用于‌资源清理‌,但不保证立即执行,依赖垃圾回收机制。
  

一、基本魔法方法
1. 对象生命周期相关
__new__(cls, [...]):实例创建时第一个调用的方法
__init__(self, [...]):构造器,初始化实例
__del__(self):析构器,对象销毁时调用
class MyClass:
    def __new__(cls, *args, **kwargs):
        print("Creating instance")
        instance = super().__new__(cls)
        return instance
    def __init__(self, value):
        print("Initializing instance")
        self.value = value
    def __del__(self):
        print("Instance is being destroyed")
obj = MyClass(10)  # 输出: Creating instance 和 Initializing instance
del obj            # 输出: Instance is being destroyed
2. 字符串表示
__str__(self):str(obj) 和 print(obj) 时调用
__repr__(self):repr(obj) 和交互式解释器中直接显示对象时调用
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
   def __str__(self):
        return f"Point({self.x}, {self.y})"
   def __repr__(self):
        return f"Point(x={self.x}, y={self.y})"
p = Point(1, 2)
print(p)      # 输出: Point(1, 2)
print(repr(p)) # 输出: Point(x=1, y=2)
二、容器类型魔法方法
1. 序列和映射方法
__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 时调用
class MyList:
    def __init__(self, data):
        self.data = list(data)
    def __len__(self):
        return len(self.data)
    def __getitem__(self, index):
        return self.data[index]
    def __setitem__(self, index, value):
        self.data[index] = value
    def __delitem__(self, index):
        del self.data[index]
    def __contains__(self, item):
        return item in self.data
ml = MyList([1, 2, 3])
print(len(ml))    # 3
print(ml[1])      # 2
print(3 in ml)    # True
2. 迭代器协议
__iter__(self):iter(obj) 或 for x in obj 时调用
__next__(self):迭代时获取下一个值
class CountDown:
    def __init__(self, start):
        self.current = start
    def __iter__(self):
        return self
    def __next__(self):
        if self.current <= 0:
            raise StopIteration
        else:
            self.current -= 1
            return self.current + 1
for num in CountDown(3):
    print(num)  # 输出: 3, 2, 1
三、数值运算魔法方法
1. 基本算术运算
__add__(self, other):+ 运算
__sub__(self, other):- 运算
__mul__(self, other):* 运算
__truediv__(self, other):/ 运算
__floordiv__(self, other):// 运算
__mod__(self, other):% 运算
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 __sub__(self, other):
        return Vector(self.x - other.x, self.y - other.y)
    def __mul__(self, scalar):
        return Vector(self.x * scalar, self.y * scalar)
    def __str__(self):
        return f"Vector({self.x}, {self.y})"
v1 = Vector(2, 4)
v2 = Vector(1, 3)
print(v1 + v2)  # Vector(3, 7)
print(v1 * 3)   # Vector(6, 12)
2. 比较运算
__eq__(self, other):== 运算
__ne__(self, other):!= 运算
__lt__(self, other):< 运算
__le__(self, other):<= 运算
__gt__(self, other):> 运算
__ge__(self, other):>= 运算
class Temperature:
    def __init__(self, celsius):
        self.celsius = celsius
    def __eq__(self, other):
        return self.celsius == other.celsius
    def __lt__(self, other):
        return self.celsius < other.celsius
    def __str__(self):
        return f"{self.celsius}°C"
t1 = Temperature(20)
t2 = Temperature(30)
print(t1 < t2)  # True
print(t1 == t2) # False
四、上下文管理
__enter__(self):进入 with 代码块时调用
__exit__(self, exc_type, exc_val, exc_tb):退出 with 代码块时调用
class Timer:
    def __enter__(self):
        import time
        self.start = time.time()
        return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        import time
        self.end = time.time()
        print(f"Elapsed time: {self.end - self.start:.2f} seconds")
with Timer():
    # 执行一些代码
    sum(range(1000000))
五、属性访问控制
__getattr__(self, name):访问不存在的属性时调用
__setattr__(self, name, value):设置属性时调用
__delattr__(self, name):删除属性时调用
__getattribute__(self, name):访问任何属性时调用(慎用)
class Restricted:
    def __init__(self):
        self.allowed = "This is allowed"
    def __getattr__(self, name):
        return f"Access to '{name}' is not allowed"
    def __setattr__(self, name, value):
        if name == 'allowed':
            super().__setattr__(name, value)
        else:
            print(f"Cannot set attribute '{name}'")
r = Restricted()
print(r.allowed)    # This is allowed
print(r.forbidden)  # Access to 'forbidden' is not allowed
r.forbidden = 123   # Cannot set attribute 'forbidden'
六、调用模拟
__call__(self, [...]):使实例可以像函数一样被调用
class Adder:
    def __init__(self, n):
        self.n = n
    def __call__(self, x):
        return self.n + x
add5 = Adder(5)
print(add5(3))  # 8
七、其他实用魔法方法
__slots__:限制实例属性,节省内存
__hash__(self):hash(obj) 时调用
__bool__(self):bool(obj) 时调用
__dir__(self):dir(obj) 时调用
class Limited:
    __slots__ = ['a', 'b']  # 只能有a和b两个属性
    def __init__(self, a, b):
        self.a = a
        self.b = b
    def __bool__(self):
        return bool(self.a or self.b)
l = Limited(0, 1)
print(bool(l))  # True
最佳实践
仅在需要时实现魔法方法:不要过度使用,只在需要特殊行为时实现
保持一致性:实现比较操作时,应实现全套比较方法
遵循约定:如 __eq__ 应该与 __hash__ 一起实现
文档化:为魔法方法添加文档字符串,说明其行为
魔法方法是 Python 强大灵活性的重要组成部分,合理使用可以使你的类更加 Pythonic 和易用。

调用顺序为 __new__ 先于 __init__,例如:

posted @ 2025-12-31 05:34  hihibig  阅读(22)  评论(0)    收藏  举报