Почему клавиши "OrderedDict" сравнивают нечувствительность к порядку?
Почему вид клавиш OrderedDict
сравнивается с нечувствительным к регистру?
>>> from collections import OrderedDict
>>> xy = OrderedDict([('x', None), ('y', None)])
>>> yx = OrderedDict([('y', None), ('x', None)])
>>> xy == yx
False
>>> xy.keys() == yx.keys()
True
В представлении "OrderedDict" должно, по-видимому, вести себя как OrderedSet, но вместо этого оно ведет себя так же, как dict.keys
(т.е. как обычный set
).
Такая же проблема в python2:
>>> xy.viewkeys() == yx.viewkeys()
True
Это разные типы, (odict_keys
является подклассом dict_keys
)
>>> type(xy.keys())
odict_keys
>>> type({}.keys())
dict_keys
И уже доступно доступное для клиентов сравнение ключей, которое они могли бы использовать тривиально, но, по-видимому, он использовался только как post-check для сравнения с богатым опытом.
Это дизайнерское решение или ошибка? Если это дизайнерское решение, где я могу найти обоснование?
Ответы
Ответ 1
Похоже, OrderedDict
делегирует реализацию различных объектов вида в общую реализацию dict
; это остается в силе даже в Python 3.5, где OrderedDict
получил ускоренную реализацию C (он делегирует конструкцию объекта _PyDictView_New
и не обеспечивает отмену для общего представления богатой функции сравнения.
В принципе, теги OrderedDict
просматривают с тем же порядком, что и их поддержка OrderedDict
(потому что для этого нет затрат), но для set
-подобных операций они действуют как set
, используя равенство контента, подмножества/надмножества и т.д.
Это делает выбор, чтобы игнорировать упорядочение имеет смысл в некоторой степени; для некоторых операций set
(например, &
, |
, ^
) возвращаемое значение равно set
без порядка (поскольку нет OrderedSet
, и даже если бы это было, какой порядок вы делаете используйте для чего-то вроде &
, где порядок может отличаться в каждом представлении?), вы получите непоследовательное поведение, если некоторые из set
-подобных операций были чувствительны к порядку, а некоторые - нет. И было бы еще более странно, когда два представления ключей OrderedDict
были чувствительны к порядку, но сравнение OrderedDict
представлений с представлениями dict
не было.
Как я заметил в комментариях, вы можете легко сравнить порядок keys
с:
from operator import eq
# Verify that keys are the same length and same set of values first for speed
# The `all` check then verifies that the known identical keys appear in the
# same order.
xy.keys() == yx.keys() and all(map(eq, xy, yx))
# If you expect equality to occur more often than not, you can save a little
# work in the "are equal" case in exchange for costing a little time in the
# "not even equal ignoring order case" by only checking length, not keys equality:
len(xy) == len(yz) and all(map(eq, xy, yx))
Ответ 2
Я не могу найти ничего опубликованного, но я полагаю, что эта логика может оправдать поведение:
Если у вас есть два словаря, d1 и d2, вы ожидаете, что сравнение ключей проверяет, имеют ли они одни и те же ключи, правильно?
def compare_dict_keys(d1, d2):
d1.keys() == d2.keys()
Эта функция должна вести себя одинаково для любых типов словарей (а OrderedDict
- тип dict
). Было бы неправильно, если бы такая функция начала возвращать False
только потому, что сортируются d1 и d2.
Другими словами, все они должны оценивать одно и то же (и они это делают):
>>> {1:2, 3:4}.keys() == {3:4, 1:2}.keys()
True
>>> {1:2, 3:4}.keys() == OrderedDict([(3,4),(1,2)]).keys()
True
>>> OrderedDict([(1,2),(3,4)]).keys() == OrderedDict([(3,4),(1,2)]).keys()
True
Но OrderedDict
является specal, не так ли?
То, что OrderedDict
предлагает вам, является гарантией заказа, когда вы перебираете его. Та же гарантия существует для OrderedDict.keys()
, но без нарушения совместимости с dict
.