在 3.8 中比较对象方法会导致不同的结果

Comparing object methods leads to different results in 3.8

提问人:planetp 提问时间:11/13/2019 最后编辑:Chris_Randsplanetp 更新时间:11/13/2019 访问量:203

问:

考虑这个简单的类:

class A:
    def method(self): pass
    def __eq__(self, other): return True

现在,如果我创建该类的两个实例并比较它们的属性,我在 Python 3.7 和 3.8 中得到不同的结果:'method'

meth1 = A().method
meth2 = A().method
print(meth1 == meth2)  # True in 3.7, False in 3.8

这是怎么回事?为什么这些方法在 3.7 中相等,但在 3.8 中不相等?这与什么有关?__eq__

比较 相等 python-3.8

评论

1赞 Yevhen Kuzmovych 11/13/2019
这与方法无关。您正在比较两个函数对象。在不同版本中返回 True/False 的事实只是 Python 实现特有的东西。A__eq__==function.__eq__
2赞 Chris_Rands 11/13/2019
@YevhenKuzmovych什么意思?我认为OP的理解是正确的,行为令人费解
0赞 Yevhen Kuzmovych 11/13/2019
@Chris_Rands我的意思是,类中的方法不会影响这一点。函数类的方法 () 以某种方式发生了变化。__eq__A__eq__A.method.__eq__
0赞 Chris_Rands 11/13/2019
@YevhenKuzmovych,如果删除该方法,您将在所有 Python 版本中获得__eq__False
2赞 Chris_Rands 11/13/2019
@YevhenKuzmovych一个针对 Python 3.8 修复的错误,但我在更新日志中找不到任何相关内容

答:

6赞 MSeifert 11/13/2019 #1

发生的事情是基于问题 16171610提交(以及关于 python-dev 的讨论)。

通过这些(选定的)评论:

在我看来,两个不同实例的实例方法是否相等取决于实例的相等性,这似乎是不合逻辑的。

其次

总而言之,我认为这部分是一个意外 并且从未设计过;

我认为实例的相等性测试意义不大 方法考虑了实例的相等性。恕我直言,这个 行为不符合无意外原则。这 正确的行为(当然,恕我直言)只是实例方法 比较等于同一实例的相同实例方法,其中 “同一实例”基于“is”而不是“==”。

此更改可以被视为错误修复,但由于它可能会破坏用户代码(不太可能),因此仅在 3.8 中合并它并作为新功能公开可能更安全。

因此,这似乎被认为是一个错误修复/功能,因为绑定方法只有在绑定在同一实例上时才应该相等,而不是当实例被认为是相等时才应该相等。在 Python <= 3.7 中,绑定方法 equality 调用实例的等效项(从而调用 your ),而在 Python 3.8 中,它会检查 .instance1 == instance2__eq__instance1 is instance2


相应的更新日志项可以在“Python 3.8.0 alpha 1”部分中找到 - 这是一个很长的项目列表,所以我在这里包含了一个副本:

  • bpo-1617161:实例(内置类的方法)的哈希值现在取决于__self__标识的哈希值,而不是其值。和实例(用户定义类的方法和内置类的一些方法,如)的哈希和相等现在依赖于__self__的标识的哈希和相等,而不是它的值。 实例不再支持排序。BuiltinMethodTypeModuleTypeMethodWrapperTypestr.__add__MethodWrapperType

评论

1赞 Tom Dalton 11/13/2019
关于python-dev的讨论非常有趣,感谢您提供这个出色而富有启发性的答案:-)