Python 为什么在只有小于等于运算符重载的情况下,大于运算符和不等于运算符仍然有效

Python 为什么在只有小于等于运算符重载的情况下,大于运算符和不等于运算符仍然有效,python,operator-overloading,Python,Operator Overloading,我目前正在研究Python是如何实现其运算符重载的。到目前为止,我发现它比C++更吸引人,尤其是在操作符如 */Cu>(或类似的算术运算符)中,它必须处理一个可以从右到左(2×x)和左到右(x* 2)的操作。 我有以下课程作为测试: from math import sqrt class Vector3: def __init__(self, x,y,z): self.x = x self.y = y self.z = z de

我目前正在研究Python是如何实现其运算符重载的。到目前为止,我发现它比C++更吸引人,尤其是在操作符如<代码> */Cu>(或类似的算术运算符)中,它必须处理一个可以从右到左(2×x)和左到右(x* 2)的操作。 我有以下课程作为测试:

from math import sqrt

class Vector3:
    def __init__(self, x,y,z):
        self.x = x
        self.y = y
        self.z = z

    def __repr__(self):
        return 'Vector3(x=%d, y=%d, z=%d)' % (self.x, self.y, self.z)

    def __str__(self):
        return '[x: %d, y: %d, z: %d]' % (self.x, self.y, self.z)

    def length(self):
        return sqrt(self.x**2 + self.y**2 + self.z**2)

    def __add__(self, vector):
        return Vector3(self.x + vector.x, self.y + vector.y, self.z + vector.z)

    def __sub__(self, vector):
        return Vector3(self.x - vector.x, self.y - vector.y, self.z - vector.z)

    def __mul__(self, scalar):
        return Vector3(self.x * scalar, self.y * scalar, self.z * scalar)

    __rmul__ = __mul__ # Right multiplication equals left multiplication (if this defers, __rmul__ has to be overwritten and defined manually)

    def __eq__(self, vector):
        return (self.x == vector.x and self.y == vector.y and self.z == vector.z)

    def __lt__(self, vector):
        return self.length() < vector.length()

    @staticmethod
    def compareAndPrint(vector1, vector2):
        if vector1 == vector2: return 'v1 == v2 since len(v1) = %f == %f = len(v2)' % (vector1.length(), vector2.length())
        elif vector1 < vector2: return 'v1 < v2 since len(v1) = %f < %f = len(v2)' % (vector1.length(), vector2.length())
        elif vector1 > vector2: return 'v1 > v2 since len(v1) = %f > %f = len(v2)' % (vector1.length(), vector2.length())

v1 = Vector3(1,2,3)
v2 = Vector3(0,-1,1)
v3 = v1 + v2
v4 = v3 - v1
v5 = v1 * 2
v6 = 2 * v1
print(v1)
print(v2)
print(v3)
print(v4)
print(v5)
print(v6)

print(Vector3.compareAndPrint(v1,v2))
print(Vector3.compareAndPrint(v2,v1))
print(Vector3.compareAndPrint(v1,v1))

Python是自动处理的还是我做了一些我没有注意到的事情来实现这一点?我唯一想到的是Python采用了
的倒数是
Python中的大多数二进制运算符都可以由任意一个操作数重载。左操作数有一种定义方法,如用于加法的
\uuuu add\uuuu
,右操作数有一种定义方法,如
\uuuu radd\uu
。我记得唯一一个只能由一个操作数重载的操作数是
中的
,它必须由右侧定义

为了便于比较,
\uu gt\uuuuuuuuu
\uuuuuuuuuuuuu
方法与
\uuuuuuuuuuuu
方法不同。这意味着当你做
left\u thing>right\u thing
left\u thing
不知道该做什么时,Python会尝试
right\u thing
。因为您已经实现了
\uuult\uuuuu
,所以这是可行的


请注意,Python不会尝试任何涉及
\uuuu le\uuuuuu
\uu ge\uuuuu
\uuuu eq\uuuuu
的操作,如果
\uu gt\uuuuu
失败。

Python中的大多数二进制运算符都可以由任一操作数重载。左操作数有一种定义方法,如用于加法的
\uuuu add\uuuu
,右操作数有一种定义方法,如
\uuuu radd\uu
。我记得唯一一个只能由一个操作数重载的操作数是
中的
,它必须由右侧定义

为了便于比较,
\uu gt\uuuuuuuuu
\uuuuuuuuuuuuu
方法与
\uuuuuuuuuuuu
方法不同。这意味着当你做
left\u thing>right\u thing
left\u thing
不知道该做什么时,Python会尝试
right\u thing
。因为您已经实现了
\uuult\uuuuu
,所以这是可行的


请注意,Python不会尝试任何涉及
\uuuu le\uuuuuu
\uu ge\uuuuu
\uuuu eq\uuuuu
的操作,如果
\uu gt\uuuuuu
失败。

这是许多人似乎不理解的Python数据模型的一部分。要在文档中追溯这一点,我们需要从二进制算术运算开始(
\uuuuu mul\uuuu
\uuuu add\uuuu
等)

我们注意到有一个和一个
方法。差异在以下文档中描述:

调用这些方法是为了用反射(交换)的操作数实现二进制算术运算(+、-、*、/、%、divmod()、pow()、**、&、^、|)仅当左操作数不支持相应的运算且操作数类型不同时,才会调用这些函数。

现在,当我们查看以下文档时:

这些方法没有交换的参数版本(当左参数不支持该操作而右参数支持该操作时使用);相反,
是彼此的反映

因此,在您的例子中发生的情况是,由于
\uugt\uugt
没有被重载,python实际上交换了参数的顺序并调用
\ugt\uugt
。相当整洁



FWIW,如果您想要构造一个可以与该类的其他实例一起排序的类,那么decorator非常有用。您只需提供
\uu lt\uuuuuuuuuu
\uuuuueq\uuuuuuu
,其余部分由装饰程序提供。

这是一些python数据模型,许多人似乎不理解。要在文档中追溯这一点,我们需要从二进制算术运算开始(
\uuuuu mul\uuuu
\uuuu add\uuuu
等)

我们注意到有一个和一个
方法。差异在以下文档中描述:

调用这些方法是为了用反射(交换)的操作数实现二进制算术运算(+、-、*、/、%、divmod()、pow()、**、&、^、|)仅当左操作数不支持相应的运算且操作数类型不同时,才会调用这些函数。

现在,当我们查看以下文档时:

这些方法没有交换的参数版本(当左参数不支持该操作而右参数支持该操作时使用);相反,
是彼此的反映

因此,在您的例子中发生的情况是,由于
\uugt\uugt
没有被重载,python实际上交换了参数的顺序并调用
\ugt\uugt
。相当整洁



FWIW,如果您想要构造一个可以与该类的其他实例一起排序的类,那么decorator非常有用。你只需提供
\ult\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。请看文章的结尾,特别是比较(v1,v2)和(v2,v1)。或者你是说别的什么?不,我的意思是在
\uult\uuuuu
\uuuuuuu eq\uuuuu
中放一些,看看它们什么时候被调用,有什么参数。啊,谢谢你的建议+1为什么不加入一些
print
s以查看调用哪些方法以及何时调用?我有打印。请看文章的结尾,特别是比较(v1,v2)和(v2,v1)。或者你是说别的什么?不,我的意思是把一些放在
里面
[x: 1, y: 2, z: 3]
[x: 0, y: -1, z: 1]
[x: 1, y: 1, z: 4]
[x: 0, y: -1, z: 1]
[x: 2, y: 4, z: 6]
[x: 2, y: 4, z: 6]
v1 > v2 since len(v1) = 3.741657 > 1.414214 = len(v2)
v1 < v2 since len(v1) = 1.414214 < 3.741657 = len(v2)
v1 == v2 since len(v1) = 3.741657 == 3.741657 = len(v2)