Почему сопоставление ** kwargs сравнивается с другим упорядоченным OrderedDict?

Согласно PEP 468:

Начиная с версии 3.6 Python сохранит порядок аргументов ключевого слова, переданный функции. Для этого собранные kwargs теперь будут упорядоченным отображением. Обратите внимание, что это не обязательно означает OrderedDict.

В этом случае, почему это упорядоченное сопоставление не учитывает сравнение равенства с каноническим упорядоченным типом отображения Python, collections.OrderedDict:

>>> from collections import OrderedDict
>>> data = OrderedDict(zip('xy', 'xy'))
>>> def foo(**kwargs):
...     return kwargs == data
... 
>>> foo(x='x', y='y')  # expected result: True
True
>>> foo(y='y', x='x')  # expected result: False
True

Хотя порядок итерации теперь сохраняется, kwargs, похоже, ведет себя так же, как обычный dict для сравнений. Python имеет C реализованный упорядоченный dict начиная с 3.5, поэтому он, возможно, мог быть использован напрямую (или, если производительность по-прежнему вызывает беспокойство, быстрее реализация с использованием тонкого подкласса 3.6 compact dict).

Почему упорядоченное сопоставление, полученное функцией, не упорядочивается при сравнении сравнений?

Ответ 1

Ответ на ваш первый "почему" заключается в том, что эта функция реализована с использованием простого dict в CPython. Как указывает @Ryan, это означает, что сравнения не будут чувствительны к порядку.

Второй "почему" вот почему это не использует OrderedDict .

Использование OrderedDict было начальным планом, как указано в первый проект PEP 486. Идея, как итерация в этом ответе, должен был собрать некоторые первичные данные, чтобы показать эффект подключения к OrderedDict , поскольку это было спорным моментом, когда идея была размещена вокруг ранее. Автор PEP даже ссылался на заказ, сохраняющий dict, являющийся еще одним вариантом в окончательном ответе в этом потоке.

После этого разговор по теме, похоже, скончался, пока не появился Python 3.6. Когда появился новый диктар, у него был хороший побочный эффект от внедрения PEP 486 из коробки (как это состояние потока Python-dev). Конкретное сообщение в этом потоке также указывает, как автор хотел, чтобы термин OrderedDict был изменен на упорядоченное сопоставление. (Это также, когда был сделан новый фиксация на PEP 468, после первоначального)

Насколько я могу судить, эта запись была сделана для того, чтобы другие реализации могли предоставлять эту функцию по своему усмотрению. У CPython и PyPy уже был dict, который легко реализовал PEP 468, другие реализации могли бы выбрать OrderedDict , другие могли бы пойти и на другую форму упорядоченного отображения.

Тем не менее, это открывает дверь для проблемы. Это означает, что теоретически при реализации Python 3.6 с OrderedDict в качестве структуры, реализующей эту функцию, сравнение будет чувствительным к порядку, а в других (CPython) - нет. (В Python 3.7 все dict должны быть упорядочены по порядку, поэтому этот момент, вероятно, будет спорным, поскольку все реализации будут использовать его для **kwargs)

Хотя это похоже на проблему, на самом деле это не так. Как указал @user2357112, на == нет гарантии. PEP 468 гарантирует только заказ. Насколько я могу судить, == определяется в основном реализацией.


Короче говоря, он сравнивает значение в CPython, потому что kwargs в CPython является dict, а a dict, потому что после 3.6 все это просто сработало.

Ответ 2

Независимо от того, что означает "упорядоченное сопоставление", если не обязательно OrderedDict, OrderedDict s == не учитывать его порядок. Документы:

Тесты равенства между объектами OrderedDict чувствительны к порядку и реализуются как list(od1.items())==list(od2.items()). Тесты равенства между объектами OrderedDict и другими объектами Mapping не зависят от порядка, как обычные словари. Это позволяет заменять объекты OrderedDict везде, где используется обычный словарь.

Ответ 3

"Упорядоченное сопоставление" означает, что отображение должно сохранять порядок. Это не означает, что порядок должен быть частью отношения отображения ==.

Цель PEP 468 состоит в том, чтобы сохранить информацию о заказе. Приказ быть частью == приведет к отстающей несовместимости без какой-либо реальной пользы для любого из вариантов использования, которые мотивировали PEP 468. Использование OrderedDict также было бы более дорогостоящим (так как OrderedDict все еще сохраняет свой собственный отдельный связанный список для отслеживания и он не может отказаться от этого связанного списка, не жертвуя большой эффективностью O в popitem и move_to_end).

Ответ 4

Просто добавьте, если вы хотите сделать эту проверку (не полагаясь на деталь реализации (которая даже тогда не будет в python 3.7)), просто сделайте

from collections import OrderedDict
>>> data = OrderedDict(zip('xy', 'xy'))
>>> def foo(**kwargs):
...     return OrderedDict(kwargs) == data

так как это гарантированно будет True.