相等运算符为内存中的2个不同对象产生True

时间:2018-11-10 07:22:03

标签: python equality

为什么当两个对象 point b 时,我的相等方法为什么会产生 True strong>是否指向内存中的2个不同对象?

import math


def main():

    point = Point(2, 3)

    print(point == Point(2, 3))

    b = Point(2, 3)

    print(id(point), id(b))


class Point:

    def __init__(self, x=0, y=0):
         self.x = x
         self.y = y

    def distance_from_origin(self):
         return math.hypot(self.x, self.y)

    def __eq__(self, other):
         return id(self.x) == id(other.x) and id(self.y) == id(other.y)

    def __repr__(self):
         return f"Point({self.x!r}, {self.y!r})"

    def __str__(self):
         return f"{self.x!r}, {self.y!r}"

如果名称 =='主要”:     main()

2 个答案:

答案 0 :(得分:2)

id对象中的

Point是不同的,因为它们是不同的对象,并且没有针对它们的缓存/中间机制(这是错误的,因为它们是可变的)。

==之所以有效,是因为在==上调用Point时,您会调用__eq__,它的编码如下:

def __eq__(self, other):
     return id(self.x) == id(other.x) and id(self.y) == id(other.y)

所以,它是错误,但是它在大多数情况下都有效,因为在CPython中从-5到256的整数进行了整数转换(进一步的测试表明,它可以使用更大的值,但不能保证)。反例:

a = 912
b = 2345

point = Point(a, b)

print(point == Point(456*2, b))

即使False,您也会得到456*2 == 912

重写为这样,这样大整数您就不会感到惊讶了

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

如果删除此__eq__方法,则会得到False,在这种情况下,未知对象上的Python默认==运算符只有对象标识才能执行比较。 / p>

但是==的目的是比较对象内容,而不是 id 。如上所示,对测试身份的相等性方法进行编码可能会导致意外。

在Python中,当人们使用==时,如果值相等,他们期望对象相等。身份是一个实现细节,只需忘记它。

(Python的先前版本要求您也定义__ne__,因为它不是__eq__的倒数,并且会导致奇怪的错误)

简而言之:除非您要编写非常复杂的低级程序,否则请不要使用is(除了is None惯用语)或id缓存和怪异的东西,或者在调试程序时。

答案 1 :(得分:0)

Python会缓存小整数(在[-5,256]范围内),因此id(self.x) == id(other.x) and id(self.y) == id(other.y)True。由于self.xother.x是内存中的相同对象。查找比较这两个对象的另一种方法,或者摆脱自定义__eq__并使用默认方法(在这种情况下,Python将为False返回point == Point(2, 3))。
有关该问题的更多信息,请参见this答案。