2025-08-22 Python进阶10——魔术方法

文章目录

  • [1 构造/销毁对象](#1 构造/销毁对象)
    • [1.1 `init`:初始化对象(常用)](#1.1 __init__:初始化对象(常用))
    • [1.2 `new`:创建对象(极少直接用)](#1.2 __new__:创建对象(极少直接用))
    • [1.3 `del`:销毁对象(慎用)](#1.3 __del__:销毁对象(慎用))
  • [2 字符串输出](#2 字符串输出)
    • [2.1 `str`:面向用户的字符串表示](#2.1 __str__:面向用户的字符串表示)
    • [2.2 `repr`:面向开发者的字符串表示](#2.2 __repr__:面向开发者的字符串表示)
  • [3 比较运算重载](#3 比较运算重载)
    • [3.1 `eq`:实现等于(==)比较](#3.1 __eq__:实现等于(==)比较)
    • [3.2 `ne`:实现不等于(!=)比较](#3.2 __ne__:实现不等于(!=)比较)
    • [3.3 `gt`:实现大于(>)比较](#3.3 __gt__:实现大于(>)比较)
    • [3.4 `ge`:实现大于等于(>=)比较](#3.4 __ge__:实现大于等于(>=)比较)
    • [3.5 `lt`:实现小于(<)比较](#3.5 __lt__:实现小于(<)比较)
    • [3.6 `le`:实现小于等于(<=)比较](#3.6 __le__:实现小于等于(<=)比较)
  • [4 算术运算重载](#4 算术运算重载)
    • [4.1 `add` 与 `radd`:实现加法(+)运算](#4.1 __add____radd__:实现加法(+)运算)
    • [4.2 `sub` 与 `rsub`:实现减法(-)运算](#4.2 __sub____rsub__:实现减法(-)运算)
    • [4.3 `mul` 与 `rmul`:实现乘法(*)运算](#4.3 __mul____rmul__:实现乘法(*)运算)
    • [4.4 `truediv` 与 `rtruediv`:实现真除法(/)运算](#4.4 __truediv____rtruediv__:实现真除法(/)运算)
    • [4.5 `floordiv` 与 `rfloordiv`:实现地板除法(//)运算](#4.5 __floordiv____rfloordiv__:实现地板除法(//)运算)
    • [4.6 `mod` 与 `rmod`:实现取模(%)运算](#4.6 __mod____rmod__:实现取模(%)运算)
    • [4.7 `pow` 与 `rpow`:实现幂运算(**)](#4.7 __pow____rpow__:实现幂运算(**))
  • [5 容器行为重载](#5 容器行为重载)
    • [5.1 `len`:获取容器长度](#5.1 __len__:获取容器长度)
    • [5.2 `getitem`:访问容器元素](#5.2 __getitem__:访问容器元素)
    • [5.3 `setitem`:设置容器元素](#5.3 __setitem__:设置容器元素)
    • [5.4 `delitem`:删除容器元素](#5.4 __delitem__:删除容器元素)
    • [5.5 `contains`:判断元素是否存在](#5.5 __contains__:判断元素是否存在)
    • [5.6 `iter`:迭代容器元素](#5.6 __iter__:迭代容器元素)
  • [6 上下文管理器](#6 上下文管理器)
    • [6.1 `enter`:进入上下文时准备资源](#6.1 __enter__:进入上下文时准备资源)
    • [6.2 `exit`:退出上下文时清理资源](#6.2 __exit__:退出上下文时清理资源)
  • [7 可调用对象](#7 可调用对象)
    • [7.1 `call`:使对象可像函数一样调用](#7.1 __call__:使对象可像函数一样调用)
  • [8 属性访问控制相关魔术方法](#8 属性访问控制相关魔术方法)
    • [8.1 `getattr`:访问不存在的属性时](#8.1 __getattr__:访问不存在的属性时)
    • [8.2 `getattribute`:访问任何属性时](#8.2 __getattribute__:访问任何属性时)
    • [8.3 `setattr`:设置属性时](#8.3 __setattr__:设置属性时)
    • [8.4 `delattr`:删除属性时](#8.4 __delattr__:删除属性时)
  • [9 描述符协议相关魔术方法](#9 描述符协议相关魔术方法)
    • [9.1 `get`:获取描述符值时](#9.1 __get__:获取描述符值时)
    • [9.2 `set`:设置描述符值时](#9.2 __set__:设置描述符值时)
    • [9.3 `delete`:删除描述符值时](#9.3 __delete__:删除描述符值时)
  • [10 数值类型转换相关魔术方法](#10 数值类型转换相关魔术方法)
    • [10.1 `int`:转换为整数](#10.1 __int__:转换为整数)
    • [10.2 `float`:转换为浮点数](#10.2 __float__:转换为浮点数)
    • [10.3 `bool`:转换为布尔值](#10.3 __bool__:转换为布尔值)
    • [10.4 `complex`:转换为复数](#10.4 __complex__:转换为复数)
  • [11 使用建议](#11 使用建议)

在 Python 中, 魔术方法 (又称 "特殊方法",以双下划线 __ 开头和结尾)是一组自带的 "隐藏工具",它们能让我们自定义类的行为(比如加减运算、打印显示、容器操作等),让代码更简洁、更符合直觉。

魔术方法不需要我们手动调用(比如不会直接写 obj.__init__()),而是在特定场景下由 Python 自动触发(比如创建对象时自动执行 __init__)。

1 构造/销毁对象

这类方法控制对象的创建、初始化和销毁,是最基础的魔术方法。

魔术方法 触发时机 作用
__new__ 创建类的实例时(比 __init__ 早) 创建对象(分配内存)
__init__ 创建实例后自动执行 初始化对象(设置属性)
__del__ 对象被垃圾回收时 销毁对象(释放资源)

1.1 __init__:初始化对象(常用)

创建实例时,Python 会自动调用 __init__ 给对象设置初始属性。
注意:它不是 "创建对象" 的方法,而是 "初始化已创建对象" 的方法。

python 复制代码
class Student:
    # 定义 __init__,self 代表实例本身,name/age 是创建实例时需要传入的参数
    def __init__(self, name, age):
        self.name = name  # 给实例绑定 name 属性
        self.age = age    # 给实例绑定 age 属性

# 创建实例时,自动触发 __init__,传入 name 和 age
stu1 = Student("小明", 18)
print(stu1.name)  # 输出:小明(__init__ 已帮我们设置好属性)
print(stu1.age)   # 输出:18

1.2 __new__:创建对象(极少直接用)

__new__ 是 Python 中唯一能创建对象的魔术方法 ,它会先分配内存,再把创建好的对象传给 __init__ 初始化。

通常无需自定义,只有在 "单例模式"(一个类只能创建一个实例)等特殊场景才会用。

python 复制代码
class Singleton:
    # 用一个类属性存储唯一实例
    _instance = None

    # __new__ 必须返回创建的对象,参数 cls 代表当前类
    def __new__(cls, *args, **kwargs):
        # 如果还没有实例,就创建一个
        if cls._instance is None:
            cls._instance = super().__new__(cls)  # 调用父类的 __new__ 创建对象
        # 无论是否新建,都返回同一个实例
        return cls._instance

# 测试:两个实例其实是同一个对象
obj1 = Singleton()
obj2 = Singleton()
print(obj1 is obj2)  # 输出:True(地址相同,是同一个实例)

1.3 __del__:销毁对象(慎用)

当对象不再被使用(没有变量引用它),Python 会自动调用 __del__ 释放资源(比如关闭文件、断开数据库连接)。
注意 :无法确定 __del__ 何时执行(由垃圾回收机制决定),不建议依赖它做关键操作。

python 复制代码
class FileHandler:
    def __init__(self, filename):
        self.file = open(filename, "w")  # 打开文件
        print("文件已打开")

    # 销毁对象时关闭文件
    def __del__(self):
        self.file.close()
        print("文件已关闭(__del__ 触发)")

# 创建实例(打开文件)
fh = FileHandler("test.txt")
# 手动删除引用(让对象被回收)
del fh  # 输出:文件已关闭(__del__ 触发)

2 字符串输出

当我们用 print(obj)str(obj) 查看对象时,Python 会自动调用这类方法,默认情况下会显示 "类名 + 内存地址"(比如 <__main__.Student object at 0x00000123456789AB>),很不友好。自定义这类方法可以让输出更直观。

魔术方法 触发时机 作用
__str__ print(obj)str(obj) 给用户看的 "友好字符串"
__repr__ repr(obj)、交互式环境直接输 obj 时 给开发者看的 "精确字符串"(可用于重建对象)

2.1 __str__:面向用户的字符串表示

python 复制代码
class Book:
    def __init__(self, title, author):
        self.title = title
        self.author = author
        
    def __str__(self):
        return f"《{self.title}》(作者:{self.author})"

book = Book("Python编程入门", "张三")
print(book)  # 输出: 《Python编程入门》(作者:张三)
print(str(book))  # 输出: 《Python编程入门》(作者:张三)

2.2 __repr__:面向开发者的字符串表示

__repr__ 主要用于调试,返回的字符串应尽可能精确地描述对象,理想情况下可以用该字符串重建对象。

python 复制代码
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        
    def __repr__(self):
        return f"Point(x={self.x}, y={self.y})"

p = Point(3, 5)
print(repr(p))  # 输出: Point(x=3, y=5)
# 在交互式环境中直接输入 p 也会显示 __repr__ 的结果

3 比较运算重载

和算术运算类似,==>< 等比较操作也对应专门的魔术方法。比如 a == b 会触发 a.__eq__(b)a > b 会触发 a.__gt__(b)

魔术方法 对应运算 作用
__eq__ a == b 等于
__ne__ a != b 不等于(默认是 not __eq__,一般不用重写)
__gt__ a > b 大于
__lt__ a < b 小于
__ge__ a >= b 大于等于(默认是 __gt__ or __eq__
__le__ a <= b 小于等于(默认是 __lt__ or __eq__

3.1 __eq__:实现等于(==)比较

__eq__ 定义了对象的相等判断逻辑,当使用 == 运算符时自动调用。

python 复制代码
class Student:
    def __init__(self, student_id):
        self.student_id = student_id  # 学号唯一标识学生
        
    def __eq__(self, other):
        # 两个学生学号相同则认为相等
        if isinstance(other, Student):
            return self.student_id == other.student_id
        return False

s1 = Student(1001)
s2 = Student(1001)
s3 = Student(1002)
print(s1 == s2)  # 输出: True
print(s1 == s3)  # 输出: False

3.2 __ne__:实现不等于(!=)比较

__ne__ 方法用于定义 "不等于" 比较的逻辑,当使用 != 运算符时自动调用。默认情况下,它返回 not __eq__ 的结果,也可以根据需要自定义实现。

python 复制代码
class Employee:
    def __init__(self, id):
        self.id = id  # 员工ID
        
    def __ne__(self, other):
        """判断两个员工的ID是否不同"""
        if isinstance(other, Employee):
            return self.id != other.id
        return True  # 与非Employee类型比较视为不同

# 测试
e1 = Employee(1001)
e2 = Employee(1002)
e3 = Employee(1001)
print(e1 != e2)  # 输出: True(ID不同)
print(e1 != e3)  # 输出: False(ID相同)
print(e1 != "employee")  # 输出: True(与非Employee类型比较)

3.3 __gt__:实现大于(>)比较

__gt__ 定义了对象的大于判断逻辑,当使用 > 运算符时自动调用。

python 复制代码
class Score:
    def __init__(self, value):
        self.value = value
        
    def __gt__(self, other):
        # 分数值大的认为更大
        return self.value > other.value

s1 = Score(95)
s2 = Score(88)
print(s1 > s2)  # 输出: True

3.4 __ge__:实现大于等于(>=)比较

__ge__ 方法用于定义 "大于等于" 比较的逻辑,当使用 >= 运算符时自动调用,返回布尔值表示比较结果。

python 复制代码
class Weight:
    def __init__(self, kg):
        self.kg = kg  # 重量(千克)
        
    def __ge__(self, other):
        """判断当前重量是否大于等于另一个重量"""
        if isinstance(other, Weight):
            return self.kg >= other.kg
        raise TypeError("只能与Weight类型进行比较")

# 测试
w1 = Weight(10)
w2 = Weight(8)
w3 = Weight(10)
print(w1 >= w2)  # 输出: True(10kg >= 8kg)
print(w1 >= w3)  # 输出: True(10kg >= 10kg)
print(w2 >= w1)  # 输出: False(8kg >= 10kg 不成立)

3.5 __lt__:实现小于(<)比较

__lt__ 方法用于定义 "小于" 比较的逻辑,当使用 < 运算符比较两个对象时自动调用。该方法应返回布尔值,表示当前对象是否小于另一个对象。

python 复制代码
class Product:
    def __init__(self, price):
        self.price = price  # 产品价格
        
    def __lt__(self, other):
        """判断当前产品价格是否小于另一个产品价格"""
        if isinstance(other, Product):
            return self.price < other.price
        # 处理与非Product类型比较的情况
        raise TypeError("只能与Product类型进行比较")

# 测试
p1 = Product(99.9)
p2 = Product(149.9)
print(p1 < p2)  # 输出: True(99.9 < 149.9)
print(p2 < p1)  # 输出: False(149.9 < 99.9 不成立)

3.6 __le__:实现小于等于(<=)比较

__le__ 方法用于定义 "小于等于" 比较的逻辑,当使用 <= 运算符时自动调用,返回布尔值表示比较结果。

python 复制代码
class Student:
    def __init__(self, score):
        self.score = score  # 学生分数
        
    def __le__(self, other):
        """判断当前学生分数是否小于等于另一个学生分数"""
        if isinstance(other, Student):
            return self.score <= other.score
        raise TypeError("只能与Student类型进行比较")

# 测试
s1 = Student(85)
s2 = Student(90)
s3 = Student(85)
print(s1 <= s2)  # 输出: True(85 <= 90)
print(s1 <= s3)  # 输出: True(85 <= 85)
print(s2 <= s1)  # 输出: False(90 <= 85 不成立)

4 算术运算重载

我们可以让自定义类的实例支持 +-*/ 等运算,只需实现对应的魔术方法。比如 a + b 会自动触发 a.__add__(b)

除了基本运算方法外,还有对应的反向方法,用于处理运算顺序相反的情况(如 b + aa 不支持加法时,会调用 b 的反向方法)。

魔术方法 对应运算 作用 反向方法
__add__ a + b 加法 __radd__
__sub__ a - b 减法 __rsub__
__mul__ a * b 乘法 __rmul__
__truediv__ a / b 真除法(返回浮点数) __rtruediv__
__floordiv__ a // b 地板除法(返回整数) __rfloordiv__
__mod__ a % b 取模 __rmod__
__pow__ a ** b 乘方 __rpow__

4.1 __add____radd__:实现加法(+)运算

__add__ 方法用于定义 "加法" 运算的逻辑,当使用 + 运算符时自动调用。__radd__ 作为反向方法,当左侧对象不支持加法运算时,会调用右侧对象的 __radd__ 方法。

python 复制代码
class Number:
    def __init__(self, value):
        self.value = value
        
    def __add__(self, other):
        """定义当前对象 + 另一个对象的逻辑"""
        if isinstance(other, Number):
            return Number(self.value + other.value)
        elif isinstance(other, (int, float)):
            return Number(self.value + other)
        return NotImplemented  # 不支持的类型返回NotImplemented
        
    def __radd__(self, other):
        """定义另一个对象 + 当前对象的逻辑(反向加法)"""
        # 对于加法,a + b 与 b + a 逻辑相同,直接调用 __add__
        return self.__add__(other)
        
    def __str__(self):
        return str(self.value)

# 测试
n1 = Number(5)
n2 = Number(3)
print(n1 + n2)  # 输出: 8(调用n1.__add__(n2))
print(n1 + 2)   # 输出: 7(调用n1.__add__(2))
print(2 + n1)   # 输出: 7(2不支持加法,调用n1.__radd__(2))

4.2 __sub____rsub__:实现减法(-)运算

__sub__ 方法用于定义 "减法" 运算的逻辑,当使用 - 运算符时自动调用。__rsub__ 作为反向方法,处理 b - ab 不支持减法时的情况。

python 复制代码
class Length:
    def __init__(self, cm):
        self.cm = cm  # 长度(厘米)
        
    def __sub__(self, other):
        """定义当前对象 - 另一个对象的逻辑"""
        if isinstance(other, Length):
            return Length(self.cm - other.cm)
        elif isinstance(other, (int, float)):
            return Length(self.cm - other)
        return NotImplemented
        
    def __rsub__(self, other):
        """定义另一个对象 - 当前对象的逻辑(反向减法)"""
        if isinstance(other, (int, float)):
            return Length(other - self.cm)
        return NotImplemented
        
    def __str__(self):
        return f"{self.cm}cm"

# 测试
l1 = Length(10)
l2 = Length(4)
print(l1 - l2)  # 输出: 6cm(调用l1.__sub__(l2))
print(l1 - 3)   # 输出: 7cm(调用l1.__sub__(3))
print(15 - l1)  # 输出: 5cm(调用l1.__rsub__(15))

4.3 __mul____rmul__:实现乘法(*)运算

__mul__ 方法用于定义 "乘法" 运算的逻辑,当使用 * 运算符时自动调用。__rmul__ 作为反向方法,处理 b * ab 不支持乘法时的情况。

python 复制代码
class Vector2D:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        
    def __mul__(self, scalar):
        """定义向量 * 标量的逻辑(向量缩放)"""
        if isinstance(scalar, (int, float)):
            return Vector2D(self.x * scalar, self.y * scalar)
        return NotImplemented
        
    def __rmul__(self, scalar):
        """定义标量 * 向量的逻辑(反向乘法)"""
        # 对于标量乘法,a * v 与 v * a 逻辑相同
        return self.__mul__(scalar)
        
    def __str__(self):
        return f"Vector2D({self.x}, {self.y})"

# 测试
v = Vector2D(2, 3)
print(v * 2)    # 输出: Vector2D(4, 6)(调用v.__mul__(2))
print(3 * v)    # 输出: Vector2D(6, 9)(调用v.__rmul__(3))

4.4 __truediv____rtruediv__:实现真除法(/)运算

__truediv__ 方法用于定义 "真除法" 运算的逻辑,当使用 / 运算符时自动调用,返回浮点数结果。__rtruediv__ 处理反向除法情况。

python 复制代码
class Quantity:
    def __init__(self, amount):
        self.amount = amount
        
    def __truediv__(self, other):
        """定义当前对象 / 另一个对象的逻辑"""
        if isinstance(other, Quantity):
            return Quantity(self.amount / other.amount)
        elif isinstance(other, (int, float)):
            return Quantity(self.amount / other)
        return NotImplemented
        
    def __rtruediv__(self, other):
        """定义另一个对象 / 当前对象的逻辑(反向除法)"""
        if isinstance(other, (int, float)):
            return Quantity(other / self.amount)
        return NotImplemented
        
    def __str__(self):
        return str(self.amount)

# 测试
q1 = Quantity(10)
q2 = Quantity(2)
print(q1 / q2)  # 输出: 5.0(调用q1.__truediv__(q2))
print(q1 / 5)   # 输出: 2.0(调用q1.__truediv__(5))
print(20 / q1)  # 输出: 2.0(调用q1.__rtruediv__(20))

4.5 __floordiv____rfloordiv__:实现地板除法(//)运算

__floordiv__ 方法用于定义 "地板除法" 运算的逻辑,当使用 // 运算符时自动调用,返回整数结果(向下取整)。__rfloordiv__ 处理反向地板除法情况。

python 复制代码
class Item:
    def __init__(self, count):
        self.count = count  # 物品数量
        
    def __floordiv__(self, other):
        """定义当前对象 // 另一个对象的逻辑(整除)"""
        if isinstance(other, Item):
            return Item(self.count // other.count)
        elif isinstance(other, int):
            return Item(self.count // other)
        return NotImplemented
        
    def __rfloordiv__(self, other):
        """定义另一个对象 // 当前对象的逻辑(反向地板除法)"""
        if isinstance(other, int):
            return Item(other // self.count)
        return NotImplemented
        
    def __str__(self):
        return str(self.count)

# 测试
i1 = Item(10)
i2 = Item(3)
print(i1 // i2)  # 输出: 3(调用i1.__floordiv__(i2))
print(i1 // 4)   # 输出: 2(调用i1.__floordiv__(4))
print(15 // i1)  # 输出: 1(调用i1.__rfloordiv__(15))

4.6 __mod____rmod__:实现取模(%)运算

__mod__ 方法用于定义 "取模" 运算的逻辑,当使用 % 运算符时自动调用,返回除法的余数。__rmod__ 处理反向取模情况。

python 复制代码
class Clock:
    def __init__(self, hour):
        self.hour = hour % 24  # 确保小时在0-23之间
        
    def __mod__(self, other):
        """定义当前时间 % 另一个值的逻辑(取模)"""
        if isinstance(other, int):
            return Clock(self.hour % other)
        return NotImplemented
        
    def __rmod__(self, other):
        """定义另一个值 % 当前时间的逻辑(反向取模)"""
        if isinstance(other, int):
            return other % self.hour
        return NotImplemented
        
    def __str__(self):
        return f"{self.hour}时"

# 测试
c = Clock(25)  # 初始化时自动取模24,实际为1时
print(c % 12)   # 输出: 1时(调用c.__mod__(12))
print(30 % c)   # 输出: 30 % 1 = 0(调用c.__rmod__(30))

4.7 __pow____rpow__:实现幂运算(**)

__pow__ 方法用于定义 "幂运算" 的逻辑,当使用 ** 运算符时自动调用,如 a** b 表示 ab 次方。__rpow__ 处理反向幂运算情况。

python 复制代码
class Power:
    def __init__(self, base):
        self.base = base
        
    def __pow__(self, exponent):
        """定义当前对象 **指数的逻辑(幂运算)"""
        if isinstance(exponent, (int, float, Power)):
            # 如果指数是Power对象,取其base值
            exp_val = exponent.base if isinstance(exponent, Power) else exponent
            return Power(self.base **exp_val)
        return NotImplemented
        
    def __rpow__(self, base):
        """定义基数** 当前对象的逻辑(反向幂运算)"""
        if isinstance(base, (int, float)):
            return Power(base **self.base)
        return NotImplemented
        
    def __str__(self):
        return str(self.base)

# 测试
p = Power(2)
print(p** 3)     # 输出: 8(调用p.__pow__(3),2^3=8)
print(3 **p)     # 输出: 9(调用p.__rpow__(3),3^2=9)

p2 = Power(3)
print(p** p2)    # 输出: 8(调用p.__pow__(p2),2^3=8)

5 容器行为重载

Python 中的列表([])、字典({})等容器,支持 len()(求长度)、obj[key](索引 / 键访问)、for in(迭代)等操作。我们可以让自定义类也支持这些行为,只需实现对应的魔术方法。

魔术方法 触发时机 主要作用
__len__ len(obj) 返回对象长度
__getitem__ obj[key] 获取指定键 / 索引的元素
__setitem__ obj[key] = value 设置指定键 / 索引的元素
__delitem__ del obj[key] 移除指定位置的元素
__contains__ item in obj 运算符时 判断元素是否存在
__iter__ for item in obj 循环时 返回迭代器

5.1 __len__:获取容器长度

__len__ 方法用于定义容器的长度计算逻辑,当调用 len() 函数时自动触发,返回一个整数表示容器中元素的数量。

python 复制代码
class ShoppingCart:
    def __init__(self):
        self.items = []  # 存储购物车中的商品
        
    def add_item(self, item):
        """添加商品到购物车"""
        self.items.append(item)
        
    def __len__(self):
        """返回购物车中商品的数量"""
        return len(self.items)

# 测试
cart = ShoppingCart()
cart.add_item("苹果")
cart.add_item("香蕉")
cart.add_item("橙子")

print(len(cart))  # 输出: 3(购物车中有3件商品)

5.2 __getitem__:访问容器元素

__getitem__ 方法用于定义通过键或索引访问容器元素的逻辑,当使用 obj[key] 语法时自动触发,返回指定位置的元素。支持整数索引、切片和键访问。

python 复制代码
class CustomList:
    def __init__(self, data):
        self.data = data  # 存储列表数据
        
    def __getitem__(self, key):
        """支持索引和切片访问元素"""
        # 对索引进行范围检查
        if isinstance(key, int):
            if key < 0:
                key = len(self.data) + key
            if 0 <= key < len(self.data):
                return self.data[key]
            raise IndexError("索引超出范围")
        # 支持切片操作
        elif isinstance(key, slice):
            return self.data[key]
        else:
            raise TypeError("索引必须是整数或切片")

# 测试
cl = CustomList(["a", "b", "c", "d", "e"])
print(cl[0])     # 输出: a(访问单个元素)
print(cl[-1])    # 输出: e(访问最后一个元素)
print(cl[1:4])   # 输出: ['b', 'c', 'd'](切片访问)

5.3 __setitem__:设置容器元素

__setitem__ 方法用于定义为容器指定位置设置元素的逻辑,当使用 obj[key] = value 语法时自动触发,将值存储到指定位置。

python 复制代码
class MutableArray:
    def __init__(self, size, default=0):
        self.size = size
        self.data = [default] * size  # 初始化指定大小的数组
        
    def __setitem__(self, index, value):
        """设置指定索引位置的元素值"""
        if isinstance(index, int):
            # 处理负索引
            if index < 0:
                index = self.size + index
            if 0 <= index < self.size:
                self.data[index] = value
                return
            raise IndexError("索引超出数组范围")
        raise TypeError("索引必须是整数")
        
    def __getitem__(self, index):
        """获取指定索引位置的元素值"""
        if isinstance(index, int):
            if index < 0:
                index = self.size + index
            if 0 <= index < self.size:
                return self.data[index]
            raise IndexError("索引超出数组范围")
        raise TypeError("索引必须是整数")

# 测试
arr = MutableArray(5)  # 创建大小为5的数组,默认值为0
arr[0] = 10
arr[2] = 20
arr[-1] = 30

print(arr[0])   # 输出: 10
print(arr[2])   # 输出: 20
print(arr[-1])  # 输出: 30

5.4 __delitem__:删除容器元素

__delitem__ 方法用于定义删除容器中指定位置元素的逻辑,当使用 del obj[key] 语法时自动触发,移除指定位置的元素。

python 复制代码
class TodoList:
    def __init__(self):
        self.tasks = []  # 存储待办任务
        
    def add_task(self, task):
        """添加任务"""
        self.tasks.append(task)
        
    def __delitem__(self, index):
        """删除指定索引的任务"""
        if isinstance(index, int):
            if 0 <= index < len(self.tasks) or -len(self.tasks) <= index < 0:
                del self.tasks[index]
                return
            raise IndexError("任务索引不存在")
        raise TypeError("索引必须是整数")
        
    def __str__(self):
        return str(self.tasks)

# 测试
todo = TodoList()
todo.add_task("学习Python")
todo.add_task("锻炼身体")
todo.add_task("阅读书籍")

print(todo)  # 输出: ['学习Python', '锻炼身体', '阅读书籍']

del todo[1]  # 删除索引为1的任务
print(todo)  # 输出: ['学习Python', '阅读书籍']

5.5 __contains__:判断元素是否存在

__contains__ 方法用于定义判断元素是否存在于容器中的逻辑,当使用 item in objitem not in obj 语法时自动触发,返回布尔值表示判断结果。

python 复制代码
class BookCollection:
    def __init__(self):
        self.books = set()  # 用集合存储书籍,提高查找效率
        
    def add_book(self, book_title):
        """添加书籍到集合"""
        self.books.add(book_title)
        
    def __contains__(self, book_title):
        """判断书籍是否在集合中"""
        return book_title in self.books

# 测试
collection = BookCollection()
collection.add_book("Python编程入门")
collection.add_book("数据结构与算法")

print("Python编程入门" in collection)  # 输出: True
print("机器学习实战" in collection)    # 输出: False
print("数据结构与算法" not in collection)  # 输出: False

5.6 __iter__:迭代容器元素

__iter__ 方法用于定义容器的迭代逻辑,当使用 for 循环遍历容器时自动触发,返回一个迭代器对象(通常是容器自身或内置迭代器),配合 __next__ 方法实现元素遍历。

python 复制代码
class NumberRange:
    def __init__(self, start, end, step=1):
        self.start = start
        self.end = end
        self.step = step
        
    def __iter__(self):
        """返回迭代器,用于遍历范围内的数字"""
        self.current = self.start
        return self
        
    def __next__(self):
        """定义每次迭代返回的下一个值"""
        if (self.step > 0 and self.current < self.end) or \
           (self.step < 0 and self.current > self.end):
            value = self.current
            self.current += self.step
            return value
        # 迭代结束时抛出StopIteration异常
        raise StopIteration

# 测试
# 遍历1到10的偶数
for num in NumberRange(2, 11, 2):
    print(num, end=" ")  # 输出: 2 4 6 8 10
    
print()

# 遍历10到1的奇数
for num in NumberRange(9, 0, -2):
    print(num, end=" ")  # 输出: 9 7 5 3 1

6 上下文管理器

上下文管理器用于定义对象在 with 语句中的行为,通过实现 __enter____exit__ 方法,可以实现资源的自动分配与释放,确保资源在使用后得到正确处理(如文件关闭、数据库连接断开等)。

魔术方法 调用时机 主要作用
__enter__ 进入 with 代码块时 准备资源(如打开文件、建立连接),返回的对象将赋值给 as 后的变量
__exit__ 退出 with 代码块时(无论正常退出还是异常退出) 清理资源(如关闭文件、断开连接),处理可能的异常

6.1 __enter__:进入上下文时准备资源

__enter__ 方法在进入 with 代码块时被调用,主要用于准备所需资源(如打开文件、建立数据库连接等)。该方法的返回值会被赋值给 with 语句中 as 后面的变量,供 with 块内部使用。

python 复制代码
class DatabaseConnection:
    def __init__(self, db_name):
        self.db_name = db_name
        self.connection = None  # 数据库连接对象
        
    def __enter__(self):
        """建立数据库连接并返回连接对象"""
        print(f"连接到数据库: {self.db_name}")
        # 模拟建立数据库连接
        self.connection = f"Connection to {self.db_name}"
        return self.connection  # 返回连接对象给as后的变量

    # 后面会实现__exit__方法

6.2 __exit__:退出上下文时清理资源

__exit__ 方法在退出 with 代码块时被调用(无论代码块正常执行完毕还是因异常中断),主要用于清理资源(如关闭文件、断开连接等)。它接收三个参数,用于处理可能发生的异常:

  • exc_type:异常类型(若没有异常则为 None
  • exc_val:异常实例(若没有异常则为 None
  • exc_tb:异常追踪信息(若没有异常则为 None
python 复制代码
class DatabaseConnection:
    def __init__(self, db_name):
        self.db_name = db_name
        self.connection = None
        
    def __enter__(self):
        print(f"连接到数据库: {self.db_name}")
        self.connection = f"Connection to {self.db_name}"
        return self.connection
        
    def __exit__(self, exc_type, exc_val, exc_tb):
        """关闭数据库连接,处理可能的异常"""
        print(f"关闭数据库连接: {self.db_name}")
        self.connection = None  # 模拟关闭连接
        
        # 处理异常(如果有的话)
        if exc_type:
            print(f"发生异常: {exc_type.__name__} - {exc_val}")
            # 返回True表示异常已处理,不会向外传播
            # 返回False表示异常未处理,会继续向外传播
            return True  # 此处选择处理异常

# 测试正常情况
with DatabaseConnection("mydb") as conn:
    print(f"使用连接: {conn} 执行操作")
# 输出:
# 连接到数据库: mydb
# 使用连接: Connection to mydb 执行操作
# 关闭数据库连接: mydb

# 测试异常情况
with DatabaseConnection("mydb") as conn:
    print("执行操作中...")
    raise ValueError("数据格式错误")  # 主动抛出异常
# 输出:
# 连接到数据库: mydb
# 执行操作中...
# 关闭数据库连接: mydb
# 发生异常: ValueError - 数据格式错误

7 可调用对象

可调用对象是指可以像函数一样被调用的对象。在 Python 中,通过实现 __call__ 魔术方法,我们可以让自定义类的实例具备可调用性,使对象能够以 obj() 的形式被调用,就像调用函数一样。

魔术方法 调用时机 主要作用
__call__ obj() 形式调用对象时 定义对象被调用时的行为,可以接收参数并返回结果

7.1 __call__:使对象可像函数一样调用

__call__ 方法用于定义对象被调用时的逻辑,当以 obj() 形式调用对象时自动触发。它可以接收任意数量的参数(包括位置参数和关键字参数),并返回处理结果,使对象具备类似函数的功能。

python 复制代码
class Calculator:
    def __init__(self, operator):
        self.operator = operator  # 存储运算符(+、-、*、/)
        
    def __call__(self, a, b):
        """定义对象被调用时的计算逻辑"""
        if self.operator == "+":
            return a + b
        elif self.operator == "-":
            return a - b
        elif self.operator == "*":
            return a * b
        elif self.operator == "/":
            if b == 0:
                raise ValueError("除数不能为零")
            return a / b
        else:
            raise ValueError(f"不支持的运算符: {self.operator}")

# 创建可调用对象(加法计算器)
add = Calculator("+")
print(add(3, 5))  # 输出: 8(对象像函数一样被调用)

# 创建减法计算器
subtract = Calculator("-")
print(subtract(10, 4))  # 输出: 6

# 创建乘法计算器
multiply = Calculator("*")
print(multiply(7, 6))  # 输出: 42

带状态的可调用对象

__call__ 方法的一个重要特性是可以访问对象的状态(属性),因此可调用对象可以在多次调用之间保持状态,这是普通函数难以做到的。

python 复制代码
class Counter:
    def __init__(self, start=0):
        self.count = start  # 初始化计数器起始值
        
    def __call__(self, step=1):
        """每次调用计数器,增加指定步长并返回当前值"""
        self.count += step
        return self.count

# 创建计数器对象,从0开始
counter = Counter()

print(counter())    # 输出: 1(默认步长为1)
print(counter(2))   # 输出: 3(步长为2,1+2=3)
print(counter(5))   # 输出: 8(步长为5,3+5=8)
print(counter.count)  # 输出: 8(直接访问当前状态)

带关键字参数的可调用对象

__call__ 方法支持关键字参数,使调用更加灵活:

python 复制代码
class TextProcessor:
    def __init__(self, default_case="lower"):
        self.default_case = default_case  # 默认大小写处理方式
        
    def __call__(self, text, case=None):
        """处理文本大小写,可通过参数覆盖默认设置"""
        # 如果调用时未指定case,使用默认设置
        case = case or self.default_case
        
        if case == "lower":
            return text.lower()
        elif case == "upper":
            return text.upper()
        elif case == "title":
            return text.title()
        else:
            return text

# 创建文本处理器,默认转为小写
processor = TextProcessor()

print(processor("Hello World"))  # 输出: hello world(默认转为小写)
print(processor("hello world", case="upper"))  # 输出: HELLO WORLD(转为大写)
print(processor("hello world", case="title"))  # 输出: Hello World(首字母大写)

8 属性访问控制相关魔术方法

属性访问控制允许自定义类对属性的访问、设置、删除等操作进行精确控制,通过实现对应的魔术方法,可以在属性操作时添加验证、日志、计算等逻辑,增强类的安全性和灵活性。

魔术方法 调用时机 主要作用
__getattr__ 访问不存在的属性时 定义访问不存在属性的处理逻辑
__getattribute__ 访问任何属性时(包括存在的) 定义所有属性访问的统一处理逻辑
__setattr__ 设置属性时(包括新增和修改) 定义设置属性的验证或处理逻辑
__delattr__ 删除属性时 定义删除属性的限制或处理逻辑

8.1 __getattr__:访问不存在的属性时

__getattr__ 方法在访问对象不存在的属性时被调用,接收属性名作为参数,可以返回默认值、计算值或抛出异常,避免因访问不存在的属性而直接报错。

python 复制代码
class User:
    def __init__(self, name, age):
        self.name = name
        self.age = age
        
    def __getattr__(self, attr):
        """处理访问不存在属性的情况"""
        # 为常见的不存在属性提供默认值或提示
        if attr == "email":
            return f"{self.name.lower()}@example.com"  # 生成默认邮箱
        elif attr == "address":
            return "未填写地址"  # 返回默认值
        else:
            # 对于其他不存在的属性,抛出 AttributeError
            raise AttributeError(f"User 对象没有属性 '{attr}'")

# 测试
user = User("Alice", 30)
print(user.name)    # 输出: Alice(访问存在的属性,不触发 __getattr__)
print(user.email)   # 输出: alice@example.com(访问不存在的属性,触发 __getattr__)
print(user.address) # 输出: 未填写地址(访问不存在的属性,触发 __getattr__)

# 访问完全不存在的属性
try:
    print(user.phone)
except AttributeError as e:
    print(e)  # 输出: User 对象没有属性 'phone'

8.2 __getattribute__:访问任何属性时

__getattribute__ 方法在访问任何 属性(包括存在的和不存在的)时都会被调用,优先级高于 __getattr__。可以用于对所有属性访问进行统一控制(如日志记录、权限验证等),但需谨慎使用,避免递归调用。

python 复制代码
class SecureData:
    def __init__(self, data):
        self.data = data
        self.secret = "敏感信息"
        
    def __getattribute__(self, attr):
        """控制所有属性的访问逻辑"""
        # 记录访问日志
        print(f"访问属性: {attr}")
        
        # 对敏感属性进行访问控制
        if attr == "secret":
            # 模拟权限检查
            has_permission = False  # 假设没有权限
            if not has_permission:
                raise PermissionError("没有访问敏感信息的权限")
        
        # 获取属性值(注意:必须使用 super().__getattribute__ 避免递归)
        return super().__getattribute__(attr)

# 测试
data = SecureData({"name": "测试数据"})
print(data.data)  # 输出: 访问属性: data → {'name': '测试数据'}

# 尝试访问敏感属性
try:
    print(data.secret)
except PermissionError as e:
    print(e)  # 输出: 没有访问敏感信息的权限

注意 :在 __getattribute__ 中访问当前对象的属性时,必须使用 super().__getattribute__(attr)object.__getattribute__(self, attr),直接使用 self.attr 会导致无限递归。

8.3 __setattr__:设置属性时

__setattr__ 方法在设置任何属性(包括新增和修改)时被调用,接收属性名和属性值作为参数,可以对属性值进行验证、转换或限制,确保属性值符合预期。

python 复制代码
class Product:
    def __init__(self, name, price):
        self.name = name  # 触发 __setattr__
        self.price = price  # 触发 __setattr__
        
    def __setattr__(self, attr, value):
        """控制属性设置的逻辑"""
        # 对价格进行验证
        if attr == "price":
            if not isinstance(value, (int, float)):
                raise TypeError("价格必须是数字类型")
            if value < 0:
                raise ValueError("价格不能为负数")
            # 验证通过,设置属性(注意避免递归)
            super().__setattr__(attr, value)
        # 对名称进行验证
        elif attr == "name":
            if not isinstance(value, str) or len(value.strip()) == 0:
                raise ValueError("商品名称必须是非空字符串")
            super().__setattr__(attr, value.strip())
        # 允许设置其他属性
        else:
            super().__setattr__(attr, value)

# 测试
try:
    # 价格为负数(无效)
    p1 = Product("手机", -1000)
except ValueError as e:
    print(e)  # 输出: 价格不能为负数

try:
    # 名称为空(无效)
    p2 = Product("", 2000)
except ValueError as e:
    print(e)  # 输出: 商品名称必须是非空字符串

# 有效属性设置
p3 = Product(" 笔记本电脑 ", 5999)
print(p3.name)  # 输出: 笔记本电脑(自动去除了首尾空格)
print(p3.price) # 输出: 5999

注意 :在 __setattr__ 中设置属性时,必须使用 super().__setattr__(attr, value),直接使用 self.attr = value 会导致无限递归。

8.4 __delattr__:删除属性时

__delattr__ 方法在删除属性时被调用,接收属性名作为参数,可以限制某些关键属性的删除,确保对象的完整性。

python 复制代码
class Person:
    def __init__(self, name, id_card):
        self.name = name
        self.id_card = id_card  # 身份证号为关键属性,不允许删除
        
    def __delattr__(self, attr):
        """控制属性删除的逻辑"""
        # 禁止删除关键属性
        if attr == "id_card":
            raise AttributeError("身份证号是关键属性,不允许删除")
        
        # 允许删除其他属性(注意避免递归)
        super().__delattr__(attr)

# 测试
person = Person("张三", "110101199001011234")

# 删除普通属性(允许)
del person.name
try:
    print(person.name)
except AttributeError:
    print("name 属性已被删除")

# 尝试删除关键属性(禁止)
try:
    del person.id_card
except AttributeError as e:
    print(e)  # 输出: 身份证号是关键属性,不允许删除

9 描述符协议相关魔术方法

描述符协议是 Python 中实现属性访问控制的高级机制,通过定义 __get____set____delete__ 方法,可以创建一个描述符对象,用于管理另一个类的属性。描述符可以实现复杂的属性逻辑,如类型检查、值验证、懒加载等,广泛应用于 ORM 框架、数据验证等场景。

魔术方法 调用时机 主要作用
__get__ 访问描述符管理的属性时 返回属性值,可添加获取逻辑
__set__ 设置描述符管理的属性时 处理属性赋值,可添加验证逻辑
__delete__ 删除描述符管理的属性时 处理属性删除,可添加限制逻辑

9.1 __get__:获取描述符值时

__get__ 方法在访问描述符管理的属性时被调用,接收三个参数:self(描述符实例)、instance(被管理的类实例)和 owner(被管理的类)。该方法返回属性的当前值,可在返回前添加计算、转换等逻辑。

python 复制代码
class Temperature:
    """温度描述符,将摄氏度转换为华氏度返回"""
    def __init__(self, celsius=0):
        self.celsius = celsius  # 存储摄氏度
        
    def __get__(self, instance, owner):
        """获取值时,返回华氏度(摄氏度 * 1.8 + 32)"""
        if instance is None:
            return self  # 类访问时返回描述符自身
        return self.celsius * 1.8 + 32

class Weather:
    # 使用描述符管理temperature属性
    temperature = Temperature()

# 测试
weather = Weather()
print(weather.temperature)  # 输出: 32.0(默认0摄氏度 → 32华氏度)

# 类访问时返回描述符自身
print(Weather.temperature)  # 输出: <__main__.Temperature object at 0x...>

9.2 __set__:设置描述符值时

__set__ 方法在设置描述符管理的属性时被调用,接收三个参数:self(描述符实例)、instance(被管理的类实例)和 value(要设置的值)。该方法可对值进行验证、转换后再存储,确保属性值符合预期。

python 复制代码
class PositiveNumber:
    """正数描述符,确保属性值为正数"""
    def __init__(self, name):
        self.name = name  # 存储属性名,用于在实例字典中保存值
        
    def __get__(self, instance, owner):
        """获取值时,从实例字典中读取"""
        return instance.__dict__[self.name]
        
    def __set__(self, instance, value):
        """设置值时,验证是否为正数"""
        if not isinstance(value, (int, float)):
            raise TypeError("值必须是数字类型")
        if value <= 0:
            raise ValueError("值必须是正数")
        # 验证通过,存储到实例字典中
        instance.__dict__[self.name] = value

class Product:
    # 使用描述符管理价格和库存属性
    price = PositiveNumber("price")
    stock = PositiveNumber("stock")
    
    def __init__(self, name, price, stock):
        self.name = name
        self.price = price  # 触发 __set__ 验证
        self.stock = stock  # 触发 __set__ 验证

# 测试
try:
    # 价格为负数(无效)
    p1 = Product("手机", -1000, 50)
except ValueError as e:
    print(e)  # 输出: 值必须是正数

try:
    # 库存为零(无效)
    p2 = Product("电脑", 5000, 0)
except ValueError as e:
    print(e)  # 输出: 值必须是正数

# 有效设置
p3 = Product("耳机", 299, 100)
print(p3.price)  # 输出: 299
print(p3.stock)  # 输出: 100

9.3 __delete__:删除描述符值时

__delete__ 方法在删除描述符管理的属性时被调用,接收两个参数:self(描述符实例)和 instance(被管理的类实例)。该方法可限制某些重要属性的删除,或在删除时执行清理操作。

python 复制代码
class ProtectedAttribute:
    """受保护的属性描述符,限制删除操作"""
    def __init__(self, name, value):
        self.name = name
        self.value = value
        
    def __get__(self, instance, owner):
        return self.value
        
    def __set__(self, instance, value):
        self.value = value
        
    def __delete__(self, instance):
        """限制删除操作,关键属性不允许删除"""
        if self.name in ["id", "ssn"]:  # 身份证号、社会安全号等关键属性
            raise PermissionError(f"属性 '{self.name}' 是关键属性,不允许删除")
        # 允许删除非关键属性
        self.value = None

class User:
    # 使用描述符管理关键属性
    id = ProtectedAttribute("id", "1001")
    ssn = ProtectedAttribute("ssn", "123-45-6789")
    address = ProtectedAttribute("address", "未知地址")

# 测试
user = User()

# 尝试删除关键属性
try:
    del user.id
except PermissionError as e:
    print(e)  # 输出: 属性 'id' 是关键属性,不允许删除

# 尝试删除非关键属性(允许)
del user.address
print(user.address)  # 输出: None(已被清空)

10 数值类型转换相关魔术方法

数值类型转换魔术方法允许自定义类的实例支持内置数值类型(如 intfloatboolcomplex)的转换,通过实现这些方法,可以定义对象转换为特定数值类型时的行为,使自定义对象能更自然地参与数值运算和判断。

魔术方法 对应转换函数 调用时机 主要作用
__int__ int(obj) 调用 int() 转换对象时 定义对象转换为整数的逻辑
__float__ float(obj) 调用 float() 转换对象时 定义对象转换为浮点数的逻辑
__bool__ bool(obj) 调用 bool() 转换对象或判断真假时 定义对象的布尔值判断逻辑
__complex__ complex(obj) 调用 complex() 转换对象时 定义对象转换为复数的逻辑

10.1 __int__:转换为整数

__int__ 方法在调用 int(obj) 时被触发,返回一个整数,表示将对象转换为整数的结果。常用于定义对象的整数表示形式。

python 复制代码
class Distance:
    """距离类,存储米为单位的距离"""
    def __init__(self, meters):
        self.meters = meters
        
    def __int__(self):
        """转换为整数时,返回米的整数部分"""
        return int(self.meters)

# 测试
d1 = Distance(150.8)
print(int(d1))  # 输出: 150(调用 __int__ 方法)

d2 = Distance(200)
print(int(d2))  # 输出: 200

10.2 __float__:转换为浮点数

__float__ 方法在调用 float(obj) 时被触发,返回一个浮点数,表示将对象转换为浮点数的结果。常用于需要精确数值表示的场景。

python 复制代码
class Weight:
    """重量类,存储千克为单位的重量"""
    def __init__(self, kg):
        self.kg = kg
        
    def __float__(self):
        """转换为浮点数时,返回千克的浮点值"""
        return float(self.kg)

# 测试
w1 = Weight(75)
print(float(w1))  # 输出: 75.0(调用 __float__ 方法)

w2 = Weight(62.5)
print(float(w2))  # 输出: 62.5

10.3 __bool__:转换为布尔值

__bool__ 方法在调用 bool(obj) 或需要判断对象真假时(如 if 语句、逻辑运算)被触发,返回 TrueFalse。如果未定义 __bool__,Python 会使用 __len__ 方法的结果(非零为 True),如果两者都未定义,所有对象默认视为 True

python 复制代码
class Inventory:
    """库存类,存储商品数量"""
    def __init__(self, count):
        self.count = count  # 商品数量
        
    def __bool__(self):
        """库存大于0则为True,否则为False"""
        return self.count > 0

# 测试
inv1 = Inventory(10)
print(bool(inv1))  # 输出: True(库存大于0)

inv2 = Inventory(0)
print(bool(inv2))  # 输出: False(库存为0)

# 在条件判断中自动触发
if inv1:
    print("库存充足")  # 执行此句
else:
    print("库存不足")

10.4 __complex__:转换为复数

__complex__ 方法在调用 complex(obj) 时被触发,返回一个复数(形式为 real + imag*j),表示将对象转换为复数的结果。常用于科学计算场景。

python 复制代码
class Vector:
    """二维向量类,存储x和y分量"""
    def __init__(self, x, y):
        self.x = x  # 实部
        self.y = y  # 虚部
        
    def __complex__(self):
        """转换为复数时,x为实部,y为虚部"""
        return complex(self.x, self.y)

# 测试
v1 = Vector(3, 4)
print(complex(v1))  # 输出: (3+4j)(调用 __complex__ 方法)

v2 = Vector(0, 5)
print(complex(v2))  # 输出: 5j

综合应用示例

以下实现一个类可以同时实现多个数值转换方法,使其能灵活地参与各种数值操作:

python 复制代码
class DataValue:
    """数据值类,支持多种数值转换"""
    def __init__(self, value):
        self.value = value
        
    def __int__(self):
        return int(round(self.value))  # 四舍五入为整数
        
    def __float__(self):
        return float(self.value)
        
    def __bool__(self):
        return self.value != 0  # 非零值为True
        
    def __complex__(self):
        return complex(self.value, self.value * 0.5)  # 虚部为实部的一半

# 测试
data = DataValue(3.7)
print(int(data))     # 输出: 4
print(float(data))   # 输出: 3.7
print(bool(data))    # 输出: True
print(complex(data)) # 输出: (3.7+1.85j)

data2 = DataValue(0)
print(bool(data2))   # 输出: False

11 使用建议

  1. 谨慎使用:只在确实需要时实现魔术方法
  2. 保持一致性:
    • 实现__eq__时也应实现__hash__
    • 实现比较运算符时最好实现全套
  3. 性能考虑:魔术方法会被频繁调用,应保持高效
  4. 文档说明:明确记录每个魔术方法的行为
  5. 避免过度使用:不是所有类都需要成为"全能选手"
相关推荐
weixin_3077791329 分钟前
C++进程监视器与自动启动程序
开发语言·c++·算法
花妖大人35 分钟前
Python和LLM问题
python·llm
草莓熊Lotso1 小时前
【C语言强化训练16天】--从基础到进阶的蜕变之旅:Day12
c语言·开发语言·c++·刷题
不喜欢学数学er1 小时前
算法第五十三天:图论part04(第十一章)
开发语言·python·图论
你怎么知道我是队长1 小时前
python---构造函数、析构函数
开发语言·python
CF14年老兵1 小时前
深入浅出 Python 一等函数:一份友好的全面解析
后端·python·trae
heeheeai1 小时前
jvm对象内存占用
开发语言·jvm·内存分析
ALex_zry1 小时前
Golang云端编程深度指南:架构本质与高阶实践
开发语言·架构·golang
jumin18062 小时前
python采用jdbc连接oracle
python·oracle
Evand J2 小时前
【PSINS工具箱】MATLAB例程,二维平面上的组合导航,EKF融合速度、位置和IMU数据,4维观测量
开发语言·matlab·平面