В тесте два результата имеют одинаковое содержимое, но могут быть разными объектами: какой вид сравнения следует выбрать для проверки результата?
Для проверки одинакового содержимого используйте равенство через оператор ==. Он сравнивает значения согласно протоколу __eq__. Оператор is проверяет идентичность — являются ли два имени ссылками на один и тот же объект — и подходит для специальных случаев вроде сравнения с None.
Python представляет значения как объекты, у которых есть идентичность, тип и содержимое. Разделение равенства и идентичности позволяет отличать совпадение данных от совместного использования одного объекта в памяти.
Механизм __eq__ нужен для пользовательских типов: класс может определить, какие объекты считать равными по смыслу. Проверка is, напротив, не сравнивает содержимое и не переопределяется обычным методом класса.
Если проверять результат через is, тест может случайно зависеть от того, вернул ли код тот же экземпляр объекта. Два независимых списка с одинаковыми элементами обычно равны, но не идентичны.
Обратная ошибка также опасна: замена is на == при проверке специального маркера может скрыть проблему. Например, пользовательский объект теоретически может сравниваться равным None, хотя самим объектом None не является.
a == b вызывает логику сравнения равенства: обычно Python обращается к __eq__ одного из объектов с учётом правил разрешения метода. Результат может быть не только встроенным bool, если тип реализует специальную семантику сравнения.
a is b проверяет, что ссылки указывают на один объект. Идентичность объекта сохраняется в течение его жизни, но совпадение идентичности не следует использовать как доказательство равенства значений.
Кэширование некоторых объектов, например малых целых чисел или строк, может привести к неожиданному совпадению идентичности. Такое поведение не должно использоваться для сравнения произвольных значений.
Практическое правило простое: для данных используйте ==, для проверки именно объекта-синглтона — is. Наиболее распространённый пример — проверка отсутствующего значения через is None.
В примере списки равны по содержимому, но созданы как два разных объекта. None проверяется через is, потому что требуется установить идентичность со специальным объектом None, а не вычислять пользовательское равенство.
В API-функции значение None означает, что параметр не был задан, а пустой список означает явно переданный пустой набор. Разработчик использовал проверку равенства для определения отсутствия параметра.
Вариант с == кажется коротким, но допускает пользовательские типы с нестандартным __eq__ и смешивает отсутствие значения с обычным сравнением. Вариант с проверкой через is None точно фиксирует требуемую семантику.
Выбранное решение — использовать is None для специального значения и == для сравнения содержимого. В результате пустой список и отсутствие параметра обрабатываются раздельно, а поведение не зависит от перегруженного сравнения пользовательских объектов.
== вернуть не bool?Да. Протокол равенства допускает пользовательскую реализацию, возвращающую объект, который затем используется в логическом контексте или обрабатывается напрямую. Поэтому выражение равенства не всегда означает немедленное получение обычного булева значения.
is?Интерпретатор может переиспользовать некоторые неизменяемые объекты или создавать их совместно. Это оптимизация реализации, а не контракт семантики сравнения значений. Код должен использовать == для значений, даже если в конкретном запуске is случайно дал тот же результат.
__eq__?Унаследованное поведение обычно сравнивает объекты по идентичности, поэтому два разных экземпляра такого класса не считаются равными. Если класс определяет собственное равенство, оно может сравнивать экземпляры по выбранным атрибутам; при этом разработчику также важно согласовать поведение __hash__, если объекты должны использоваться как ключи словаря или элементы множества.