使对象 x 使得 "x in [x]" returns False
Making an object x such that "x in [x]" returns False
如果我们做出这样的病态土豆:
>>> class Potato:
... def __eq__(self, other):
... return False
... def __hash__(self):
... return random.randint(1, 10000)
...
>>> p = Potato()
>>> p == p
False
我们可以这样打断sets和dicts(注意:即使__eq__
returnsTrue
也是一样的破坏它们的哈希):
>>> p in {p}
False
>>> p in {p: 0}
False
还有 len({p: 0, p: 0}) == 2
和 {p: 0}[p]
引发 KeyError,基本上所有与映射相关的东西都会按预期退出 window。
但是我没想到的是我们不能打破列表
>>> p in [p]
True
这是为什么?似乎 list.__contains__
迭代,但它是第一个 checking identity 在检查相等性之前。由于身份并非意味着相等(例如参见 NaN 对象),列表在身份比较中短路的原因是什么?
list
、tuple
等确实在相等性检查之前进行身份检查,这种行为的动机是 these invariants:
assert a in [a]
assert a in (a,)
assert [a].count(a) == 1
for a in container:
assert a in container # this should ALWAYS be true
不幸的是,dict
s、set
s 和朋友们通过哈希操作,所以如果你弄乱了它们,你确实可以有效地破坏它们。
有关历史,请参阅 this issue and this issue。
一般来说,打破身份意味着平等的假设可以打破 Python 中的各种事物。 NaN 确实打破了这个假设,因此 NaN 打破了 Python 中的一些东西。讨论可以在this Python bug. In a pre-release version of Python 3.0, reliance on this assumption was removed, but the resolution of the bug was to put it back in (i.e., make Python 3 give the same behavior as Python 2, in which the identity check shortcut is done). The documentation中找到Python 3正确地说:
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)
.
但是,Python 2 的文档似乎不正确,因为它说:
For the list and tuple types, x in y is true if and only if there exists an index i such that x == y[i] is true.
如果你愿意,你可以提出一个关于这个的文档错误,尽管这是一个非常深奥的问题,所以我怀疑它会在任何人的优先列表中排在前列。
如果我们做出这样的病态土豆:
>>> class Potato:
... def __eq__(self, other):
... return False
... def __hash__(self):
... return random.randint(1, 10000)
...
>>> p = Potato()
>>> p == p
False
我们可以这样打断sets和dicts(注意:即使__eq__
returnsTrue
也是一样的破坏它们的哈希):
>>> p in {p}
False
>>> p in {p: 0}
False
还有 len({p: 0, p: 0}) == 2
和 {p: 0}[p]
引发 KeyError,基本上所有与映射相关的东西都会按预期退出 window。
但是我没想到的是我们不能打破列表
>>> p in [p]
True
这是为什么?似乎 list.__contains__
迭代,但它是第一个 checking identity 在检查相等性之前。由于身份并非意味着相等(例如参见 NaN 对象),列表在身份比较中短路的原因是什么?
list
、tuple
等确实在相等性检查之前进行身份检查,这种行为的动机是 these invariants:
assert a in [a]
assert a in (a,)
assert [a].count(a) == 1
for a in container:
assert a in container # this should ALWAYS be true
不幸的是,dict
s、set
s 和朋友们通过哈希操作,所以如果你弄乱了它们,你确实可以有效地破坏它们。
有关历史,请参阅 this issue and this issue。
一般来说,打破身份意味着平等的假设可以打破 Python 中的各种事物。 NaN 确实打破了这个假设,因此 NaN 打破了 Python 中的一些东西。讨论可以在this Python bug. In a pre-release version of Python 3.0, reliance on this assumption was removed, but the resolution of the bug was to put it back in (i.e., make Python 3 give the same behavior as Python 2, in which the identity check shortcut is done). The documentation中找到Python 3正确地说:
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)
.
但是,Python 2 的文档似乎不正确,因为它说:
For the list and tuple types, x in y is true if and only if there exists an index i such that x == y[i] is true.
如果你愿意,你可以提出一个关于这个的文档错误,尽管这是一个非常深奥的问题,所以我怀疑它会在任何人的优先列表中排在前列。