wim*_*wim 25 python python-internals
如果我们制作这样的病态土豆:
>>> class Potato:
... def __eq__(self, other):
... return False
... def __hash__(self):
... return random.randint(1, 10000)
...
>>> p = Potato()
>>> p == p
False
Run Code Online (Sandbox Code Playgroud)
我们可以通过这种方式打破集合和切换(注意:即使__eq__返回True它也是一样的,它正在破坏它们的哈希):
>>> p in {p}
False
>>> p in {p: 0}
False
Run Code Online (Sandbox Code Playgroud)
此外len({p: 0, p: 0}) == 2,并{p: 0}[p]引发KeyError,基本上所有与映射相关的东西都会出现,如预期的那样.
但我没想到的是我们不能打破名单
>>> p in [p]
True
Run Code Online (Sandbox Code Playgroud)
这是为什么?它似乎是list.__contains__迭代,但它首先在检查相等性之前检查身份.由于不是身份意味着相等的情况(例如参见NaN对象),列表在身份比较中短路的原因是什么?
Eth*_*man 11
list,tuple等等,不相等性检查前确实做了一个身份检查,而这种行为是由动机这些不变量:
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
Run Code Online (Sandbox Code Playgroud)
不幸的是,dicts,sets和朋友通过哈希来操作,所以如果你搞砸那些你确实可以有效地打破它们.
一般来说,打破身份意味着平等的假设可以打破Python中的各种事物.确实NaN打破了这个假设,因此NaN在Python中打破了一些东西.讨论可以在这个Python bug中找到.在Python 3.0的预发布版本中,删除了对此假设的依赖,但该错误的解决方案是将其重新放入(即,使Python 3提供与Python 2相同的行为,其中身份检查快捷方式是完成).Python 3 的文档正确地说:
对于容器类型,例如list,tuple,set,frozenset,dict或collections.deque,表达式
x in y等效于any(x is e or x == e for e in y).
但是,似乎Python 2的文档不正确,因为它说:
对于列表和元组类型,当且仅当存在索引i使得x == y [i]为真时,y中的x才为真.
如果你愿意的话,你可以提出一个关于这个的文档错误,虽然这是一个非常深奥的问题,所以我怀疑它在任何人的优先级列表上都会很高.
| 归档时间: |
|
| 查看次数: |
1140 次 |
| 最近记录: |