Будет ли порядок сохранения ключей важен при работе со словарём в Python
Что проверяют
Знаете ли вы, что гарантирует язык, и как это влияет на тесты. Для QA вопрос почти всегда уходит в практику: можно ли сравнивать словари и JSON из ответа API, если ключи пришли в другом порядке.
Как отвечать
Коротко: порядок вставки сохраняется, но на равенство словарей он не влияет.
- гарантия: с Python 3.7 сохранение порядка вставки закреплено в спецификации языка. В CPython 3.6 так уже работало, но считалось деталью реализации;
- обновление и удаление: новое значение для существующего ключа позицию не меняет, а удаление и повторная вставка переносят ключ в конец;
- сравнение:
{"a": 1, "b": 2} == {"b": 2, "a": 1}даётTrue. Порядок учитывает только сравнение двухOrderedDictмежду собой; - сериализация:
json.dumpsпишет ключи в порядке вставки, аsort_keys=Trueделает вывод стабильным независимо от него; - множества: у
setпорядка нет, а для строк он может меняться между запусками из-за рандомизации хэшей (PYTHONHASHSEED).
Отсюда правило для автотестов: ответ API сравнивают после разбора, response.json() == expected, а не как строки. По спецификации JSON объект неупорядочен, и бэкенд вправе переставить поля без изменения контракта. pytest при падении такого assert сам покажет разницу по ключам.
Порядок важен там, где он часть требования: колонки CSV через csv.DictWriter с явным fieldnames, порядок полей в выгрузке, которую читает человек, снапшот текста. Тогда проверяйте его явно, например list(data.keys()) == [...].
Где спотыкаются
Отвечают «словари в Python неупорядочены». Это верно только для версий до 3.6 и выдаёт устаревшие знания.
Сравнивают JSON строками или снапшотом сырого текста. Тест краснеет от безобидной перестановки полей, и команда перестаёт ему доверять.
Полагаются на порядок set или на порядок строк из базы без ORDER BY. Локально тест зелёный, в CI падает через раз, и это классический нестабильный тест.