Python 的 list.__contains__ 应该以什么顺序调用 __eq__?
In what order should Python’s list.__contains__ invoke __eq__?
考虑以下 Python 程序:
class Foo(object):
def __init__(self, bar):
self.bar = bar
def __repr__(self):
return 'Foo(%r)' % (self.bar,)
def __eq__(self, other):
print('Foo.__eq__(%r, %r)' % (self, other))
return self.bar == other
foo1 = Foo('A')
foo2 = Foo('B')
assert foo1 not in [foo2]
在 CPython 2.7.11 和 3.5.1 下,它打印:
Foo.__eq__(Foo('A'), Foo('B'))
Foo.__eq__(Foo('B'), 'A')
但是在 PyPy 5.3.1 (2.7) 下,它打印:
Foo.__eq__(Foo('B'), Foo('A'))
Foo.__eq__(Foo('A'), 'B')
虽然 Python 3.5 的文档 states 平等应该是对称的“如果可能的话”,但有时它不是。在这种情况下,Foo.__eq__
的参数顺序变得很重要。
那么,上面的 CPython 行为是一个实现细节,还是 list
的 public 接口的一部分(意味着 PyPy 有一个错误)?请解释你为什么这么认为。
For container types such as list, tuple, set, frozenset, dict, or
collections.deque, the expression x in y
is equivalent to any(x is
e or x == e for e in y)
.
同一部分中的其他示例显示了相等性测试的相同顺序。这表明比较应该是 item_maybe_in_list.__eq__(item_actually_in_list)
,在这种情况下,这可能被认为是 PyPy 中的错误。此外,CPython 是参考实现,因此如果存在任何差异,该版本将获胜!
就是说,您应该向那个社区提出这个问题,看看他们对此有何看法。
考虑以下 Python 程序:
class Foo(object):
def __init__(self, bar):
self.bar = bar
def __repr__(self):
return 'Foo(%r)' % (self.bar,)
def __eq__(self, other):
print('Foo.__eq__(%r, %r)' % (self, other))
return self.bar == other
foo1 = Foo('A')
foo2 = Foo('B')
assert foo1 not in [foo2]
在 CPython 2.7.11 和 3.5.1 下,它打印:
Foo.__eq__(Foo('A'), Foo('B'))
Foo.__eq__(Foo('B'), 'A')
但是在 PyPy 5.3.1 (2.7) 下,它打印:
Foo.__eq__(Foo('B'), Foo('A'))
Foo.__eq__(Foo('A'), 'B')
虽然 Python 3.5 的文档 states 平等应该是对称的“如果可能的话”,但有时它不是。在这种情况下,Foo.__eq__
的参数顺序变得很重要。
那么,上面的 CPython 行为是一个实现细节,还是 list
的 public 接口的一部分(意味着 PyPy 有一个错误)?请解释你为什么这么认为。
For container types such as list, tuple, set, frozenset, dict, or collections.deque, the expression
x in y
is equivalent toany(x is e or x == e for e in y)
.
同一部分中的其他示例显示了相等性测试的相同顺序。这表明比较应该是 item_maybe_in_list.__eq__(item_actually_in_list)
,在这种情况下,这可能被认为是 PyPy 中的错误。此外,CPython 是参考实现,因此如果存在任何差异,该版本将获胜!
就是说,您应该向那个社区提出这个问题,看看他们对此有何看法。