【问题标题】:Python 2 vs Python 3 double underscore methodsPython 2 与 Python 3 双下划线方法
【发布时间】:2017-06-27 19:59:36
【问题描述】:

所以在 Python 3 中,我可以使用 object().__eq__。我目前将其用作可映射函数,相当于lambda x: x is object()。

我将它用作哨兵(因为None 与没有参数的含义不同)。

>>> import sys
>>> print(sys.version)
3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 18:41:36) [MSC v.1900 64 bit (AMD64)]
>>> object.__eq__
<slot wrapper '__eq__' of 'object' objects>
>>> object().__eq__
<method-wrapper '__eq__' of object object at 0x000002CC4E569120>

但在 Python 2 中,这不起作用:

>>> import sys
>>> print sys.version
2.7.13 (v2.7.13:a06454b1afa1, Dec 17 2016, 20:53:40) [MSC v.1500 64 bit (AMD64)]
>>> object.__eq__
<method-wrapper '__eq__' of type object at 0x0000000054AA35C0>
>>> object().__eq__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'object' object has no attribute '__eq__'
>>> dir(object)
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']

为什么没有这个功能?以及如何模拟它(与 Python 2 兼容)

$ python3 -m timeit "sentinel = object(); tests = [sentinel] * 100 + [None] * 100" "list(filter(sentinel.__eq__, tests))"
100000 loops, best of 3: 8.8 usec per loop
$ python3 -m timeit "sentinel = object(); tests = [sentinel] * 100 + [None] * 100; exec('def is_sentinel(x): return sentinel is x', locals(), globals())" "list(filter(is_sentinel, tests))"
10000 loops, best of 3: 29.1 usec per loop

【问题讨论】:

  • 这正是你不应该使用__dunder__ 这样的方法的原因。使用import operator; operator.eq
  • 或者实际使用lambda thing: thing is sentinel;平等不一定是身份。
  • @jonrsharpe 我使用的是 s = object()。为此,我认为平等被定义为身份。
  • @Artyer 但语义不同;身份让读者更清楚什么是重要的,就像你应该测试is None一样。
  • @Artyer 这是一个有趣的奥秘。我认为这与旧式和新式类之间的区别有关,这在 Python 3 中不存在。在 Python 2 中,您在 object 上看到的 __eq__ 方法似乎继承自type,而在 Python 3 中,object 有它自己的 __eq__ 方法,它没有被继承。无论如何,您应该使用operator 模块来处理这些事情。在 Python 2 的情况下,object 实例没有 __eq__,因为 object.__eq__ 属于类对象,而不是实例。即,它继承自元类type。

标签: python python-3.x compatibility python-2.x


【解决方案1】:

如果你想要一个函数来测试一个固定对象是否相等,那就是

from functools import partial
from operator import eq

equals_thing = partial(eq, thing) # instead of thing.__eq__

这与thing.__eq__ 的行为略有不同,因为它还为另一个参数提供了提供比较的机会,并且它不会返回NotImplemented。

如果您无论如何都想进行身份测试,请使用operator.is_ 而不是operator.eq:

from operator import is_

is_thing = partial(is_, thing)

如果你真的想要一个原始的__eq__ 调用、NotImplemented 和所有的 Python 3 行为,那么根据类型,你可能需要手动重新实现它。对于object,那就是

lambda x: True if x is thing else NotImplemented

在 Python 2 中,并不是每个对象都定义了 __eq__,事实上,并不是每个对象都定义了任何类型的相等比较,即使是旧式的 __cmp__。 == 的身份比较回退发生在任何对象的方法之外。

【讨论】:

  • 我不知道operator.is_。谢谢!当它允许时,我会接受它。
猜你喜欢
  • 2021-11-28
  • 2012-11-09
  • 1970-01-01
  • 2011-10-19
  • 2018-06-30
  • 2016-12-03
  • 2013-01-14
相关资源
最近更新 更多