В проверке результата Python почему is нельзя использовать вместо == для сравнения значений?
is проверяет идентичность: являются ли два имени ссылками на один и тот же объект. == проверяет равенство значений через соответствующую логику сравнения объектов. Поэтому для сравнения содержимого используют ==, а is — главным образом для проверки уникальных объектов-синглтонов, например None.
Объектная модель Python разделяет два понятия: объект может быть тем же самым экземпляром или лишь иметь такое же значение, как другой объект. Это позволяет, например, создать два независимых списка с одинаковым содержимым и одновременно поддерживать специальные уникальные объекты, с которыми сравнение по идентичности однозначно.
Такое разделение решает проблему неоднозначности: сравнение данных не должно зависеть от того, переиспользовал ли интерпретатор существующий объект или создал новый. Оптимизации вроде интернирования строк или кэширования небольших целых чисел не меняют семантику is и не должны использоваться как её основа.
Если применять is для значений, программа может случайно зависеть от способа создания объекта, версии Python или конкретной реализации интерпретатора. Два равных объекта могут иметь разные идентичности, поэтому проверка через is способна ложно сообщить, что значения различаются.
Обратная ошибка тоже опасна: == может быть перегружен, выполнять нетривиальную логику или возвращать результат нестандартного типа. Для проверки именно уникального служебного объекта нужна идентичность, а не равенство.
Оператор is сравнивает идентичность объектов: условие истинно только тогда, когда оба операнда указывают на один объект. Он не вызывает пользовательский метод равенства и не сравнивает содержимое.
Оператор == выполняет проверку равенства, обычно используя специальные методы __eq__ объектов. Результат может зависеть от типа, содержимого и переопределённой логики сравнения; для некоторых библиотечных объектов он может быть не обычным булевым значением.
Проверка is None предпочтительнее == None, потому что она точно проверяет специальный объект None и не зависит от перегруженного сравнения. Аналогично is уместен для других API, которые документируют конкретный объект-сигнал.
Нельзя делать вывод об идентичности по наблюдаемому поведению интерпретатора: одинаковые литералы иногда могут совместно использовать объект, но это деталь реализации или оптимизации. Если нужен независимый объект, его создают явно; если нужно сравнить данные, используют ==.
Функция возвращает список разрешений пользователя. Разработчик проверяет наличие пустого результата через result is [], ожидая, что условие сработает для любого пустого списка. Это неверно: литерал списка в проверке создаёт другой объект, даже если оба списка пусты.
Вариант с == [] проверяет значение, но жёстко связывает условие с конкретным типом и формой сравнения. Проверка not result обычно лучше выражает намерение проверить пустоту, однако она опирается на истинность объекта и подходит только когда пустые и иные ложные значения должны считаться эквивалентными.
Выбранное решение зависит от контракта функции: для точного распознавания отсутствия результата возвращают None и проверяют result is None; для проверки пустой коллекции используют not result; для сравнения содержимого — ==. Такой контракт не зависит от случайного переиспользования объектов и делает намерение кода явным.
1. Может ли is иногда вернуть True для разных литералов одинакового значения?
Да, интерпретатор может переиспользовать один объект, например при интернировании строк или кэшировании некоторых неизменяемых значений. Это не гарантия общего правила языка для произвольных значений, поэтому результат is нельзя переносить на другие случаи или использовать для проверки равенства.
2. Почему для None рекомендуют is None, а не == None?
None — уникальный объект, обозначающий отсутствие значения, поэтому нужна проверка именно его идентичности. Кроме того, пользовательский класс может переопределить __eq__ и сравниваться с None неожиданным образом или с побочными эффектами; is такую логику не вызывает.
3. Может ли == вернуть не bool?
Да. Контракт сравнения допускает результат, который затем приводится к истинности в условном контексте; библиотеки для массивов, например, могут возвращать поэлементный результат и запрещать его неявное сведение к одному булеву значению. Поэтому при работе с такими типами нужно использовать предусмотренные библиотекой операции сравнения, а is применять только для проверки идентичности.