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 有一个错误)?请解释你为什么这么认为。

根据 the language reference:

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 是参考实现,因此如果存在任何差异,该版本将获胜!

就是说,您应该向那个社区提出这个问题,看看他们对此有何看法。