首页 > 解决方案 > 相等运算符为内存中的 2 个不同对象生成 True

问题描述

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

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()

标签: pythonequality

解决方案


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

==有效,因为在调用==on 时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 默认运算符仅具有执行比较的对象标识。

但目的==是比较对象内容,而不是ids。如上所示,编写一个测试身份的相等方法可能会导致意外。

在 Python 中,当人们使用 时==,如果值相等,他们希望对象是相等的。身份是一个实现细节,别管它了。

(以前版本的 Python 也需要您定义__ne__,因为它不会自动反转__eq__并且可能导致奇怪的错误)

简而言之:不要使用is(除了is None成语),或者id除非你正在编写一个非常复杂的低级程序,其中包含缓存和奇怪的东西,或者在调试你的程序时。


推荐阅读