Вопрос по python, coding-style – идентичность против равенства для None в Python

16

Различные руководства по Python говорят, чтобы использоватьx is None вместоx == None, Это почему? Равенство используется для сравнения значений, поэтому естественно спросить,x имеет значениеNone, обозначенный== и неis, Может кто-нибудь объяснить, почемуis является предпочтительной формой и показывает пример, где два не дают один и тот же ответ?

Благодарю.

None не является точным значением. «Нет» часто используется для представления отсутствия значения, например, когда аргументы по умолчанию не передаются в функцию. & quot;docs.python.org/2/library/constants.html#None Mark E. Haase

Ваш Ответ

3   ответа
3

«Сравнение с синглетами, подобными None, всегда должно выполняться с помощью« is »; или "не", никогда не операторы равенства. " Вот довольно хорошее объяснение, почему:

http://jaredgrubb.blogspot.com/2009/04/python-is-none-vs-none.html

14

Причина, по которой люди используютis потому что нет никакого преимущества в использовании==, Можно писать объекты, которые сравниваются равнымиNone, но это редко.

class A(object):
    def __eq__(self, other):
        return True

print A() == None

Выход:

True

is Оператор также работает быстрее, но я не считаю этот факт важным.

@ Хамиш В каком смысле он "не имеет значения"? Этоis значение, как и любой другой объект.
Я думаю, вы также можете добавить, что есть только одинNone объект, и это не имеет значения. Так как всеNoneЭто один и тот же объект, вы должны использовать оператор идентификации объектаis, Оператор сравнения== неуместно, потому чтоNone не имеет значения.
Почемуis Оператор быстрее? Рассуждение о том, что «Никто не является бесполезным», все еще не имеет смысла ... кажется произвольным. КакNone отличный отFalse или другие ценности? Это значение равноNone... по определению user248237dfsf
@ user248237 но важно то, чтоis None а такжеis not None сказать точно, что вы имеете в виду - как указывает DietrichEpp, этоpossible тотx == None может быть перегружен, чтобы вернуть True для неNone xвозможно через баг.is подразумевает равенство (обычно см.float('nan') для единственного контрпримера), но равенство не всегда подразумевает идентичность даже при сравнении с синглетами (вам нужен синглтон на LHS, чтобы иметь__eq__ делатьreturn self is otherи не сравнивать это с чем-то, что подклассами это).is говорит, что вы имеете в виду - гораздо проще, чем правила.
@ user248237 theis оператор потенциально быстрее, потому что он не может быть перегружен - нет эквивалента цепочке вызовов, которыеa == b потенциально делает (обычно:a.__eq__(b), b.__eq__(a) и наконецa is b - первым, чтобы вернуть что-то, кромеNotImplemented выигрывает).is тестирует только одну вещь, о которой Python знает напрямую, и всегда дает вам ответ после одного теста.None быть бесценным ненадежно, но вы можете думать о нем как о нулевом указателе C - значение указателя - это то, на что он указывает, а нулевой указатель - ни на что.
11

is Ключевое слово проверяет идентичность. Это не оператор сравнения, как==, С помощьюis не только проверяет, имеют ли два аргумента одинаковое значение и / или одинаковую внутреннюю структуру, а именно: проверяет, действительно ли оба аргумента ссылаются на один и тот же объект в памяти. Это имеет множество следствий, одним из которых является то, чтоis не может быть перегружен, и другое, что поведение отличается между изменяемым и неизменным типами. Например, рассмотрим следующее:

>>> l1 = range(5)
>>> l2 = range(5)
>>> l1 == l2
True
>>> l1 is l2
False
>>> l3 = l1
>>> l1 is l3
True
>>> s1 = "abcde"
>>> s2 = "abcde"
>>> s1 == s2
True
>>> s1 is s2
True

Здесь, поскольку списки являются изменяемыми, они не могут совместно использовать местоположение в памяти, и, следовательно,is а также== привести к противоречивым результатам. С другой стороны, строки являются неизменяемыми, и поэтому их память может быть объединена в некоторых случаях. В принципе,is может надежно использоваться только для простых неизменяемых типов или в случаях, когда несколько имен указывают на один и тот же объект в памяти (например, использованиеl3 в приведенном выше примере), и его использование указывает на желание проверить идентичность, а не значение. Я бы ожидалis быть немного быстрее чем== потому что он не выполняет поиск метода, но я могу ошибаться. Конечно, для сложных контейнерных объектов, таких как списки или dicts,is должно быть намного быстрее, чем== (O (1) против O (n), предположительно). Тем не менее, вопрос скорости в основном является спорным вопросом, поскольку эти два не следует рассматривать как взаимозаменяемые.

@lvc, спасибо за разъяснения. Не стесняйтесь редактировать мой пост, если он нуждается в исправлении. Я не утверждаю, что являюсь экспертом во внутренних органах CPython или в любой другой реализации.
Я бы не стал называть схемыeq? предикат очень точный, так как многое поведение не определено. Его поведение менее точно / точноeqv?который, в свою очередь, менее конкретен / точен, чемequal?.
is только проверяет расположение памяти в CPython - в других реализациях можно совершенно свободно тестировать и другие вещи (например, PyPy обрабатывает целые числа специально, позволяя значению определять идентичность). Интернирование строк также не гарантировано. Выare прямо оis не делая поиск методов, хотя -== может выполнить два из них (по одному для каждого операнда), прежде чем вернуться к проверке идентичности, и любой из них может применить любое правило сумасшедшего равенства, которое он захочет - включая сравнение, равное одиночному.
@DietrichEpp, q.v.,gnu.org/software/mit-scheme/documentation/mit-scheme-ref/…, который указывает, чтоeq? только возвращается#t когдаeqv? будет, и чтоeq? может быть сделано как простое сравнение указателей (является ли это практикой в конкретных реализациях, я понятия не имею). Я нащупал какую-то аналогию с Pythonis в моем объяснении и по причинам, которые избегают понимания,eq? это то, что всплывает из моего подсознания. Из всех предикатов Схемы это кажется наиболее близким, хотя другой предикат Схемы является подходящим.
@DietrichEpp, прошло много времени с тех пор, как я делал любое кодирование в Схеме, но IIRCequal? ничего не делает, кроме как применитьeqv? для последовательностей / типов контейнеров, таких как векторы, cons-ячейки и т. д. В частности,equal? вернусь#t при сравнении разных объектов, хранящихся в разных местах памяти, которые структурно идентичны. Очевидно, что это не соответствует поведениюis, Кажется, я помню, чтоeq? был самым примитивным / низкоуровневым предикатом идентичности, большая часть его поведения на практике не соответствовалаeqv?и что многие ситуации зависели от реализации.

Похожие вопросы