当前位置: 首页 > news >正文

Python“魔术方法”详解:self 与 other 的角色与交互

本文深入解析了 Python 中的“特殊方法”(也称“魔术方法”),特别是以 __eq__ 为代表的、使用 (self, other) 参数对的模式。文章的核心在于阐明 self(操作符左侧对象)和 other(右侧对象)的含义,以及如何通过实现这些方法,让你自定义的类能够响应 Python 的内置运算符。

内容系统地分类并详解了:

  1. 丰富比较方法 (如 __eq__, __gt__):用于实现 ==, > 等比较。

  2. 二元算术方法 (如 __add__, __mul__):用于实现 +, * 等运算。

  3. 反向算术方法 (如 __radd__, __rmul__):用于处理当 otherself 左侧时的运算(例如 2 * my_object)。

  4. 增强赋值方法 (如 __iadd__):用于实现 += 等原地修改操作。

  5. 其他相关模式 (如 __contains__):用于实现 in 操作符。

通过 PersonVector 等类别的代码示例,清晰地展示了这些方法在实践中的调用逻辑和 NotImplemented 返回值的重要作用。


1. 丰富比较运算符 (Rich Comparison Operators)

  • __eq__(self, other)

    • 操作符: self == other

    • 详解: 检查 self 是否等于 other

  • __ne__(self, other)

    • 操作符: self != other

    • 详解: 检查 self 是否不等于 other。 (如果你没定义 __ne__,Python 会默认调用 __eq__ 并取反)。

  • __lt__(self, other)

    • 操作符: self < other

    • 详解: 检查 self 是否小于 other

  • __le__(self, other)

    • 操作符: self <= other

    • 详解: 检查 self 是否小于等于 other

  • __gt__(self, other)

    • 操作符: self > other

    • 详解: 检查 self 是否大于 other

  • __ge__(self, other)

    • 操作符: self >= other

    • 详解: 检查 self 是否大于等于 other

重要提示:NotImplemented 在实现这些方法时,如果 other 是一个你的类无法比较的类型,你应该 return NotImplemented(而不是 False)。这会给 Python 一个机会去尝试调用 other 对象的反向比较方法(例如,a == b 失败后,Python 会尝试 b == a)。

class Person:def __init__(self, name, age):self.name = nameself.age = age# 详解 __eq__def __eq__(self, other):print(f"调用 {self.name}.__eq__({other})")# 检查 other 是不是 Person 类型if isinstance(other, Person):# 如果是,我们定义“相等”为 name 和 age 都相等return self.name == other.name and self.age == other.age# 如果类型不同,我们不知道怎么比,返回 NotImplementedreturn NotImplemented# 详解 __gt__ (大于)def __gt__(self, other):print(f"调用 {self.name}.__gt__({other})")if isinstance(other, Person):# 我们定义“大于”为年龄更大return self.age > other.agereturn NotImplementeddef __repr__(self):# 方便打印时查看return f"Person('{self.name}', {self.age})"p1 = Person("Alice", 25)
p2 = Person("Alice", 25)
p3 = Person("Bob", 30)# 示例 1: == 操作
# 这会调用 p1.__eq__(p2)
# self 是 p1, other 是 p2
print(f"p1 == p2: {p1 == p2}\n") 
# 输出:
# 调用 Alice.__eq__(Person('Alice', 25))
# p1 == p2: True# 示例 2: > 操作
# 这会调用 p3.__gt__(p1)
# self 是 p3, other 是 p1
print(f"p3 > p1: {p3 > p1}\n")
# 输出:
# 调用 Bob.__gt__(Person('Alice', 25))
# p3 > p1: True# 示例 3: 和不同类型比较
# 这会调用 p1.__eq__(100)
# self 是 p1, other 是 100
print(f"p1 == 100: {p1 == 100}\n")
# 输出:
# 调用 Alice.__eq__(100)
# p1 == 100: False 
# (因为 __eq__ 返回了 NotImplemented,Python 尝试 100.__eq__(p1) 也失败,最终结果为 False)

2. 二元算术运算符 (Binary Arithmetic Operators)

这些方法用于实现 +, -, *, / 等算术运算。

  • __add__(self, other)

    • 操作符: self + other

  • __sub__(self, other)

    • 操作符: self - other

  • __mul__(self, other)

    • 操作符: self * other

  • __truediv__(self, other)

    • 操作符: self / other (真除法,例如 5 / 2 = 2.5)

  • __floordiv__(self, other)

    • 操作符: self // other (地板除,例如 5 // 2 = 2)

  • __mod__(self, other)

    • 操作符: self % other (取模)

  • __pow__(self, other)

    • 操作符: self ** other (幂运算)

  • __lshift__(self, other)

    • 操作符: self << other (按位左移)

  • __rshift__(self, other)

    • 操作符: self >> other (按位右移)

  • __and__(self, other)

    • 操作F符: self & other (按位与)

  • __or__(self, other)

    • 操作符: self | other (按位或)

  • __xor__(self, other)

    • 操作符: self ^ other (按位异或)

class Vector:def __init__(self, x, y):self.x = xself.y = y# 详解 __add__def __add__(self, other):print(f"调用 Vector({self.x}, {self.y}).__add__({other})")if isinstance(other, Vector):# 向量相加:(x1+x2, y1+y2)return Vector(self.x + other.x, self.y + other.y)return NotImplementeddef __repr__(self):return f"Vector({self.x}, {self.y})"v1 = Vector(1, 2)
v2 = Vector(10, 20)# 这会调用 v1.__add__(v2)
# self 是 v1, other 是 v2
result = v1 + v2 
print(f"结果: {result}")
# 输出:
# 调用 Vector(1, 2).__add__(Vector(10, 20))
# 结果: Vector(11, 22)

3. 反向算术运算符 (Reflected Arithmetic Operators)

这是 selfother 概念中一个非常重要的补充。

场景:当你执行 other + self 时,Python 会首先尝试调用 other.__add__(self)。如果 other(比如是一个 int)不知道如何与你的 Vector 对象相加(即 int.__add__ 失败或返回 NotImplemented),Python 就会反过来,尝试调用 self反向方法

反向方法就是在原方法名前加一个 r

  • __radd__(self, other)

    • 触发: other + self (当 other.__add__(self) 失败时)

    • 注意: 此时 self 仍然是你的对象(在 + 右侧),other 是左侧的对象。

  • __rsub__(self, other)

    • 触发: other - self

  • __rmul__(self, other)

    • 触发: other * self

  • ... (其他算术运算符都有对应的 r 版本)

示例(续上例):

class Vector:# ... (接上例的 __init__, __add__, __repr__) ...# 让我们允许向量和一个数字相乘def __mul__(self, other):print(f"调用 {self}.__mul__({other})")if isinstance(other, (int, float)):# 向量 * 2return Vector(self.x * other, self.y * other)return NotImplemented# 详解 __rmul__def __rmul__(self, other):# 当 2 * v1 时, Python 尝试 int.__mul__(v1),失败。# 于是 Python 调用 v1.__rmul__(2)# 此时 self 是 v1, other 是 2print(f"调用 {self}.__rmul__({other})")# 逻辑通常和 __mul__ 一样return self.__mul__(other)v1 = Vector(1, 2)# 示例 1: v1 * 2
# 调用 v1.__mul__(2)
print(f"v1 * 2 = {v1 * 2}\n")
# 输出:
# 调用 Vector(1, 2).__mul__(2)
# v1 * 2 = Vector(2, 4)# 示例 2: 2 * v1
# 调用 2.__mul__(v1) -> 失败 (int 不知道怎么乘 Vector)
# 于是 Python 转而调用 v1.__rmul__(2)
print(f"2 * v1 = {2 * v1}\n")
# 输出:
# 调用 Vector(1, 2).__rmul__(2)
# 调用 Vector(1, 2).__mul__(2)  (在 __rmul__ 内部又调用了 __mul__)
# 2 * v1 = Vector(2, 4)

4. 增强赋值运算符 (In-place Assignment Operators)

这些用于 +=, -=, *= 等操作。

  • __iadd__(self, other)

    • 操作符: self += other

  • __isub__(self, other)

    • 操作符: self -= other

  • __imul__(self, other)

    • 操作F符: self *= other

  • ... (其他算术运算符都有对应的 i 版本)

关键点: 这类方法应该(如果可能)直接修改 self,并且必须返回 self。如果没定义 __iadd__,Python 会退而求其次,执行 self = self + other (即调用 __add__)。

class NumberBox:def __init__(self, value):self.value = value# 详解 __iadd__def __iadd__(self, other):print(f"调用 {self}.__iadd__({other})")if isinstance(other, (int, float)):# 直接修改 self.valueself.value += other# 必须返回 selfreturn self return NotImplementeddef __repr__(self):return f"NumberBox({self.value})"box = NumberBox(10)
print(f"box 的 ID (操作前): {id(box)}")# 这会调用 box.__iadd__(5)
box += 5 print(f"box 的 ID (操作后): {id(box)}") # ID 没变
print(f"box 的新值: {box}")
# 输出:
# box 的 ID (操作前): ...
# 调用 NumberBox(10).__iadd__(5)
# box 的 ID (操作后): ... (和上面一样)
# box 的新值: NumberBox(15)

5. 其他 (self, other) 模式的方法

还有一些方法虽然参数名不叫 other,但模式是完全一样的 (self, item)(self, key)

  • __contains__(self, item)

    • 操作符: item in self

    • 详解: 检查 item 是否包含在 self 容器中。self 是容器,item 是被检查的对象。

  • __getitem__(self, key)

    • 操作符: self[key]

    • 详解: 获取 selfkey 对应的值。

  • __setitem__(self, key, value)

    • 操作符: self[key] = value

    • 详解: 设置 selfkey 对应的值为 value。(这是 (self, other, another) 的模式)

  • __delitem__(self, key)

    • 操作符: del self[key]

    • 详解: 删除 selfkey 对应的值。

示例 __contains__:

class Team:def __init__(self, members):self.members = set(members)# 详解 __contains__def __contains__(self, member_name):# self 是 my_team, member_name 就是 "Bob"print(f"调用 Team.__contains__({member_name})")return member_name in self.membersmy_team = Team(["Alice", "Bob", "Charlie"])# 这会调用 my_team.__contains__("Bob")
print(f"'Bob' in my_team: {"Bob" in my_team}")
# 输出:
# 调用 Team.__contains__(Bob)
# 'Bob' in my_team: True

总结

selfother 是 Python 运算符重载的核心。

  1. self 是操作符左侧的对象。

  2. other 是操作符右侧的对象。

  3. 比较方法__eq__ 等)用于 ==, < 等。

  4. 算术方法__add__ 等)用于 +, * 等。

  5. 反向方法__radd__ 等)用于当左侧对象(other)无法处理该操作时,Python 会反转操作,让 self(右侧对象)来尝试处理。

  6. 原地修改方法__iadd__ 等)用于 +=,应直接修改 self 并返回 self

  7. NotImplemented 是一个特殊的返回值,用于告诉 Python “我不知道怎么处理这个类型,你试试别的办法吧”(比如尝试反向操作)。

http://www.dtcms.com/a/520762.html

相关文章:

  • 每日SQL练习 -- 24年阿里(医院门诊复诊率与抗生素用药占比统计)
  • Vue项目中资源引入方式详解
  • 单页网站设计欣赏沪深300指数
  • 跨境一件代发平台温州seo关键词优化
  • mvc5网站开发网站长尾关键词排名软件
  • 阿里云渠道商:如何建立阿里云的权限模型?
  • 网站开发 只要凡科精选app
  • 玉溪市网站建设推广移动通信网站建设
  • 《算法通关指南之C++编程篇(5)----- 条件判断与循环(下)》
  • DarkZero
  • python 网站开发怎么部署龙岩有什么招聘本地网站
  • 上海兼职做网站淘宝友情链接怎么设置
  • 【Linux系统编程】程序替换:execve(execl、execlp、execle、execv、execvp、execvpe)
  • 西安市城乡房地产建设管理局网站wordpress国外主题修改
  • 巨鹿网站建设网络公司云南住房和建设厅网站
  • 前端八股文 | HTTP - 实时通信方式/前后端通信方式
  • 谈一谈ViewDragHelper的工作原理?
  • Flutter框架机制详解
  • 火山引擎推出Data Agent评测体系,并发布《2025数据智能体实践指南》
  • SpringBoot-Web开发之异常处理
  • wap网站和app的区别php网站后台建设
  • 舞阳网站建设如何引流被动加好友
  • js wordpress 菜单管理如何给网站做seo优化
  • Nginx server_name 配置详解
  • 做宣传网站网页制作素材去哪找
  • 百度地图网站开发wordpress会员权限
  • 微硕WSF2040 N沟MOSFET:汽车电动尾门“防夹升降核”
  • 网站建设投标书报价表建设电子商务网站的好处
  • 网站建设与开发教学大纲全网商机app招标
  • Less-4 GET-Error based-Double Quotes-String