Чи є різниця між ==
і is
в Python?
Так, вони мають дуже важливу різницю.
==
: перевірка рівності - семантика полягає в тому, що еквівалентні об'єкти (які необов'язково є одним і тим же об'єктом) перевірятимуться як рівні. Як зазначено в документації :
Оператори <,>, ==,> =, <= і! = Порівнюють значення двох об'єктів.
is
: перевірка на ідентичність - семантика полягає в тому, що об'єкт (як зберігається в пам'яті) є об'єктом. Знову ж таки, документація говорить :
Оператори is
і is not
тест на ідентичність об'єкта: x is y
істинно, якщо і лише тоді, коли x
і y
є тим самим об'єктом. Ідентифікація об'єкта визначається за допомогою id()
функції. x is not y
дає зворотне значення істини.
Таким чином, перевірка на ідентичність - це те саме, що перевірка рівності ідентифікаторів об'єктів. Це є,
a is b
те саме, що:
id(a) == id(b)
де id
вбудована функція, яка повертає ціле число, яке "гарантовано буде унікальним серед одночасно існуючих об'єктів" (див. help(id)
), а де a
і b
є будь-які довільні об'єкти.
Інші вказівки щодо використання
Ви повинні використовувати ці порівняння для їх семантики. Використовуйте is
для перевірки ідентичності та ==
для перевірки рівності.
Тож загалом ми використовуємо is
для перевірки особи. Зазвичай це корисно, коли ми перевіряємо наявність об'єкта, який повинен існувати лише один раз у пам'яті, який у документації позначається як "синглтон".
Випадки is
використання:
None
- значення enum (при використанні Enums з модуля enum)
- зазвичай модулі
- зазвичай об'єкти класу, що є результатом визначень класів
- зазвичай функціонують об'єкти, що є результатом визначень функцій
- все інше, що повинно існувати лише один раз у пам'яті (всі одиночні кнопки, як правило)
- конкретний об'єкт, який ви хочете за особою
Звичайні випадки використання для ==
включають:
- числа, включаючи цілі числа
- струни
- списки
- набори
- словники
- спеціальні об'єкти, що змінюються
- інші вбудовані незмінні об'єкти, в більшості випадків
Загальний випадок використання, знову ж , для ==
, це об'єкт , який ви хочете , не може бути той же об'єкт, а це може бути еквівалентно один
PEP 8 напрямків
PEP 8, офіційний посібник зі стилів Python для стандартної бібліотеки, також згадує два випадки використання дляis
:
Порівняння з одинаковими, як None
і завжди, слід проводити з операторами рівності is
або
is not
, ніколи.
Крім того, остерігайтеся писати, if x
коли ви дійсно маєте на увазі if x is not None
- наприклад, під час тестування, чи змінна або аргумент, для якого за замовчуванням None
було встановлено якесь інше значення. Інше значення може мати тип (наприклад, контейнер), який може бути помилковим у булевому контексті!
Визначення рівності від ідентичності
Якщо is
це правда, зазвичай можна зробити висновок про рівність - логічно, якщо об'єкт є самим собою, то він повинен перевірятися як рівноцінний собі.
У більшості випадків ця логіка є вірною, але вона спирається на реалізацію __eq__
спеціального методу. Як кажуть документи ,
Поведінка за замовчуванням для порівняння ( ==
та !=
) рівності базується на ідентичності об'єктів. Отже, порівняння рівності випадків з однаковою ідентичністю призводить до рівності, а порівняння рівності випадків з різними тотожностями призводить до нерівності. Мотивацією такої поведінки за замовчуванням є бажання, щоб усі об'єкти були рефлексивними (тобто x є y означає x == y).
і в інтересах послідовності рекомендує:
Порівняння рівності повинно бути рефлексивним. Іншими словами, ідентичні об'єкти повинні порівнювати:
x is y
мається на увазі x == y
Ми можемо побачити, що це поведінка за замовчуванням для користувацьких об'єктів:
>>> class Object(object): pass
>>> obj = Object()
>>> obj2 = Object()
>>> obj == obj, obj is obj
(True, True)
>>> obj == obj2, obj is obj2
(False, False)
Протипоказання також зазвичай справедливо - якщо тест чогось не є рівним, зазвичай можна зробити висновок, що вони не є одним і тим же об'єктом.
Оскільки тести на рівність можна налаштувати, цей висновок не завжди відповідає дійсності для всіх типів.
Виняток
Помітним винятком є те, що nan
він завжди перевіряється як не рівний собі:
>>> nan = float('nan')
>>> nan
nan
>>> nan is nan
True
>>> nan == nan # !!!!!
False
Перевірка ідентичності може бути набагато швидшою, ніж перевірка рівності (що може вимагати рекурсивної перевірки членів).
Але це не може бути замінено рівністю, коли ви можете знайти більш ніж один об'єкт як еквівалент.
Зауважте, що порівняння рівності списків та кортежів передбачає, що ідентичність об'єктів однакова (адже це швидка перевірка). Це може створити суперечності, якщо логіка суперечлива - як для nan
:
>>> [nan] == [nan]
True
>>> (nan,) == (nan,)
True
Попереджувальна казка:
Питання намагається використовувати is
для порівняння цілих чисел. Не слід вважати, що екземпляр цілого числа є тим самим екземпляром, що і інший, отриманий іншою посиланням. Ця історія пояснює, чому.
Коментер мав код, який спирався на те, що малі цілі числа (від -5 до 256 включно) є одинаковими в Python, замість перевірки рівності.
Ого, це може призвести до деяких підступних помилок. У мене був якийсь код, який перевіряв, якщо a є b, який працював так, як я хотів, тому що a і b, як правило, невеликі числа. Помилка трапилася лише сьогодні, через півроку виробництва, тому що a і b нарешті були досить великими, щоб їх не було кешовано. - gwg
Це працювало в розвитку. Можливо, пройшли деякі тести.
І він працював у виробництві - доки код не перевірив ціле число, що перевищує 256, і в цей момент він не вдався у виробництві.
Це збій у виробництві, який міг потрапити в перегляд коду або, можливо, за допомогою перевірки стилів.
Дозвольте підкреслити: не використовуйте is
для порівняння цілих чисел.
echo 'import sys;tt=sys.argv[1];print(tt is "foo", tt == "foo", id(tt)==id("foo"))'| python3 - foo
output :False True False
.