Python 2 对比 Python 3 双下划线方法
Python 2 vs Python 3 double underscore methods
所以在Python3中,我可以使用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
如果您想要一个函数来测试固定对象的相等性,那就是
from functools import partial
from operator import eq
equals_thing = partial(eq, thing) # instead of thing.__eq__
这与 thing.__eq__
的行为略有不同,因为它也给了另一个参数提供比较的机会,它不会 return NotImplemented
.
如果你无论如何都想进行身份测试,请使用 operator.is_
而不是 operator.eq
:
from operator import is_
is_thing = partial(is_, thing)
如果您确实想要原始 __eq__
调用的 Python 3 行为,NotImplemented
等等,那么根据类型,您可能必须手动重新实现它。对于 object
,那就是
lambda x: True if x is thing else NotImplemented
在 Python 2 中,并不是每个对象都定义了 __eq__
,事实上,并不是每个对象都定义了任何类型的相等比较,即使是旧式的 __cmp__
. ==
的身份比较回退发生在任何对象的方法之外。
所以在Python3中,我可以使用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
如果您想要一个函数来测试固定对象的相等性,那就是
from functools import partial
from operator import eq
equals_thing = partial(eq, thing) # instead of thing.__eq__
这与 thing.__eq__
的行为略有不同,因为它也给了另一个参数提供比较的机会,它不会 return NotImplemented
.
如果你无论如何都想进行身份测试,请使用 operator.is_
而不是 operator.eq
:
from operator import is_
is_thing = partial(is_, thing)
如果您确实想要原始 __eq__
调用的 Python 3 行为,NotImplemented
等等,那么根据类型,您可能必须手动重新实现它。对于 object
,那就是
lambda x: True if x is thing else NotImplemented
在 Python 2 中,并不是每个对象都定义了 __eq__
,事实上,并不是每个对象都定义了任何类型的相等比较,即使是旧式的 __cmp__
. ==
的身份比较回退发生在任何对象的方法之外。