详解 Python 的二元算术运算,为什么说减法只是语法糖?( 三 )


如果没有上述规则,Spam() - Bacon() 将得到 LessSpam,因为 Spam 不知道减掉 Bacon 应该得出 VeggieSpam 。
但是,有了上述规则,就会得到预期的结果 VeggieSpam,因为 Bacon.__rsub__() 首先会在表达式中被调用(如果计算的是 Bacon() - Spam(),那么也会得到正确的结果,因为首先会调用 Bacon.__sub__(),因此,规则里才会说两个类的不同的方法需有区别,而不仅仅是一个由 issubclass() 判断出的子类 。)
# 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 (            rhs_type is not _MISSING  # Do we care?            and rhs_type is not lhs_type  # Could RHS be a subclass?            and issubclass(rhs_type, lhs_type)  # RHS is a subclass!            and lhs_rmethod is not rhs_method  # Is __r*__ actually different?        ):            calls = call_rhs, call_lhs        elif 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}"            )推广到其它二元运算解决掉了减法运算,那么其它二元运算又如何呢?好吧,事实证明它们的操作相同,只是碰巧使用了不同的特殊/魔术方法名称 。
所以,如果我们可以推广这种方法,那么我们就可以实现 13 种操作的语义:+ 、-、*、@、/、//、%、**、<<、>>、&、^、和 | 。


推荐阅读