Есть ли какая-либо причина 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 функциями с очень большими аргументами:
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__
(это делается только один раз и затем жестко кэшируется, поскольку указал by @jsbueno), но из-за того, что таблица хеш-словаря должна выполняться __eq__
каждый раз, чтобы убедиться, что он нашел нужный объект в ведре (очевидно, недостаточно равенства хэшей).
UPDATE:
Кажется, стоит рассмотреть этот вопрос отдельно для трех ситуаций.
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
делает короткое замыкание: мгновенное сравнение огромных одинаковых строк.