【发布时间】:2016-08-05 00:32:55
【问题描述】:
x == x 没有被快速评估有什么原因吗?我希望__eq__ 会检查它的两个参数是否相同,如果是,则立即返回 True。但它没有这样做:
s = set(range(100000000))
s == s # this doesn't short-circuit, so takes ~1 sec
对于内置,x == x 总是返回 True 我认为?对于用户定义的类,我想有人可以定义不满足此属性的__eq__,但是有任何合理的用例吗?
我希望快速评估x == x 的原因是因为当memoizing functions with very large arguments:
from functools import lru_cache
@lru_cache()
def f(s):
return sum(s)
large_obj = frozenset(range(50000000))
f(large_obj) # this takes >1 sec every time
请注意,@lru_cache 对于大型对象重复缓慢的原因并不是因为它需要计算__hash__(这只完成一次,然后被@硬缓存为pointed out jsbueno),但是因为字典的哈希表每次都需要执行__eq__以确保在桶中找到正确的对象(哈希相等显然是不够的)。
更新:
看来这个问题值得针对三种情况分别考虑。
1) 用户定义类型(即非内置/标准库)。
正如@donkopotamus 指出的那样,在某些情况下x == x 不应评估为True。例如,对于numpy.array 和pandas.Series 类型,结果故意不能转换为布尔值,因为不清楚自然语义应该是什么(False 是否意味着容器为空,或者它是否意味着其中的所有项目都是 False? )。
但是在这里,python不需要做任何事情,因为如果合适的话,用户总是可以短路x == x比较自己:
def __eq__(self, other):
if self is other:
return True
# continue normal evaluation
2) Python 内置/标准库类型。
a) 非容器。
据我所知,这种情况下可能已经实现了短路 - 我无法确定,因为无论哪种方式都非常快。
b) 容器(包括str)。
正如@Karl Knechtel 评论的那样,如果在self is not other 的情况下,短路所节省的成本超过了额外开销,则添加短路可能会损害总体性能。虽然理论上是可能的,但即使在这种情况下,相对而言开销也很小(容器比较永远不会超快)。当然,在短路有帮助的情况下,可以节省大量资金。
顺便说一句,事实证明str 确实短路了:比较巨大的相同字符串是即时的。
【问题讨论】:
-
'x == x' 对于内置函数并不总是 True - 特别是,NaN(非数字)永远不等于任何东西,甚至不等于它本身。
-
我最好的猜测是“因为它会减慢所有其他比较,因此不会针对常见情况进行优化”。但是,当它是 O(1) 与 O(N) 的问题时,并且在某些情况下经常出现“罕见”案例是有实际原因的,我会支持你说应该做一个例外.不过,NaN 是该例外的一个例外……完全可以说它不应该是唯一的,并且其他用户定义的类可能有自己的原因。
-
写
x is y or x == y,简称x in (y,)。 -
@Veedrac 我会,但不在
lru_cache中,也不在字典哈希表算法中.. -
@max 包装值以避免这种情况相当简单。
标签: python python-3.x python-internals