当操作的双方是不同类型时,这样可以确保它们都有机会尝试使表达式生效 。当它们相同时,我们假设__sub__() 就能够处理好 。但是,即使两边的实现相同,你仍然要调用__rsub__(),以防其中一个对象是其它的(子)类 。
3、不关心类型现在,表达式双方都可以参与运算!但是,如果由于某种原因,某个对象的类型不支持减法怎么办(例如不支持 4 - “stuff”)?在这种情况下,__sub__ 或__rsub__ 能做的就是返回 NotImplemented 。
这是给 Python 返回的信号,它应该继续执行下一个操作,尝试使代码正常运行 。对于我们的代码,这意味着需要先检查方法的返回值,然后才能假定它起作用 。
# 减法的实现,其中表达式的左侧和右侧均可参与运算_MISSING = object()def sub(lhs: Any, rhs: Any, /) -> Any: # lhs.__sub__ lhs_type = type(lhs) try: lhs_method = debuiltins._mro_getattr(lhs_type, "__sub__") except AttributeError: lhs_method = _MISSING # lhs.__rsub__ (for knowing if rhs.__rub__ should be called first) try: lhs_rmethod = debuiltins._mro_getattr(lhs_type, "__rsub__") except AttributeError: lhs_rmethod = _MISSING # rhs.__rsub__ rhs_type = type(rhs) try: rhs_method = debuiltins._mro_getattr(rhs_type, "__rsub__") except AttributeError: rhs_method = _MISSING call_lhs = lhs, lhs_method, rhs call_rhs = rhs, rhs_method, lhs if lhs_type is not rhs_type: calls = call_lhs, call_rhs else: calls = (call_lhs,) for first_obj, meth, second_obj in calls: if meth is _MISSING: continue value = meth(first_obj, second_obj) if value is not NotImplemented: return value else: raise TypeError( f"unsupported operand type(s) for -: {lhs_type!r} and {rhs_type!r}" )
4、子类优先于父类如果你看一下__rsub__() 的文档,就会注意到一条注释 。它说如果一个减法表达式的右侧是左侧的子类(真正的子类,同一类的不算),并且两个对象的__rsub__() 方法不同,则在调用__sub__() 之前会先调用__rsub__() 。换句话说,如果 b 是 a 的子类,调用的顺序就会被颠倒 。
这似乎是一个很奇怪的特例,但它背后是有原因的 。当你创建一个子类时,这意味着你要在父类提供的操作上注入新的逻辑 。这种逻辑不一定要加给父类,否则父类在对子类操作时,就很容易覆盖子类想要实现的操作 。
具体来说,假设有一个名为 Spam 的类,当你执行 Spam() - Spam() 时,得到一个 LessSpam 的实例 。接着你又创建了一个 Spam 的子类名为 Bacon,这样,当你用 Spam 去减 Bacon 时,你得到的是 VeggieSpam 。
推荐阅读
- 万字干货,Python语法大合集,一篇文章带你入门
- 冷泡茶的做法,乌龙茶冷泡茶的好处有哪些
- EditPlus——一款小巧功能强大的老牌代码文本编辑器
- HttpClient三个超时时间详解
- 历史上著名的连环杀手 古代有名的杀手
- 辽国第五位皇帝辽景宗 辽世宗与辽穆宗的关系
- 形容外行人的歇后语 外行的歇后语是什么
- 沉鱼落雁的成语故事 沉鱼落雁是成语吗
- 处暑的气候特点 节气与气候及农业生产的关系
- 李元吉没有当皇帝的可能嘛 李建成和李元吉为什么要排挤李世民