тест not None в Python

Из них нет ни одного теста.

if val != None:

if not (val is None):

if val is not None:

Какой из них предпочтительнее и почему?


person prosseek    schedule 19.10.2010    source источник
comment
Как насчет if val: ?   -  person Siddharth Choudhary    schedule 06.11.2020
comment
Это не тот тест! Это if будет ложным, если val равно 0, , [], 0,0. и т.д., а также если это None.   -  person NickDanger66    schedule 08.11.2020


Ответы (4)


if val is not None:
    # ...

— это идиома Pythonic для проверки того, что переменная не установлена ​​в None. Эта идиома особенно полезна в случае объявления ключевых слов с параметрами по умолчанию. is проверяет личность в Python. Поскольку в работающем сценарии/программе Python присутствует один и только один экземпляр None, is является оптимальным тестом для этого. Как указывает Johnsyweb, это обсуждается в PEP 8 в разделе "Рекомендации по программированию".

Что касается того, почему это предпочтительнее, чем

if not (val is None):
    # ...

это просто часть Дзен Python: "Удобочитаемость имеет значение". Хороший Python часто близок к хорошему псевдокоду.

person gotgenes    schedule 19.10.2010
comment
кроме того, для этой цели не создана специальная семантика (это не является логическим следствием того, как построены выражения; 1 есть (не None) и 1 не None имеют два разных результата. - person Ivo van der Wijk; 26.03.2012
comment
not None возвращает True. Интересный. - person Ries; 14.06.2013
comment
@gotgenes Не всегда прав. Например: вар = ''. Если вы запустите этот код, он успешно проверит None. Следовательно, вы не можете проверить, установлено ли для переменной значение None или пустая строка. - person Ethan; 30.08.2013
comment
@Ethan val = ''; print(val is not None) печатает True, так что вы считаете неправильным? - person gotgenes; 30.08.2013
comment
@gotgenes Моей целью было проверить переменную, если для нее явно установлено значение None. Я хочу различать пустую строку и None. Пример использования: подпрограмма инициализирует val = None, а вызывающая сторона отправляет ''. - person Ethan; 06.09.2013
comment
Верно, потому что is not None гораздо читабельнее, чем not (val is None). Ясно, что это означает, что что-то противоположно ничему, как противоположность чему-то, противоположному чему-то как ничто. Намного лучше. Спасибо! - person Erik Aronesty; 08.07.2015
comment
Что касается того, почему val != None не рекомендуется: если val может быть либо None, либо более сложной вещью, такой как массив numpy, не совсем ясно, предназначено ли это для поэлементного сравнения (например: arr>0 будет создавать список индексов при котором элементы arr положительны), поэтому, если вы ожидаете, что val будет либо массивом, либо None, то arr is None — самый безопасный способ проверить это. Фактически, Python 2.7.6 генерирует предупреждение о том, что arr != None будет работать поэлементно в будущем. arr is not None также приятнее читать. - person Zak; 12.12.2016
comment
Поскольку в работающем сценарии/программе Python присутствует один и только один экземпляр None, is является оптимальным тестом для этого. Делает ли это дело для val is 0 или val is 'a'? - person nivk; 28.11.2018
comment
@nivk хороший вопрос. Маленькие целые числа и короткие строки интернированы, так что это сработает. Проблема в том, что оно зависит от значения: val = 'asdasdasgerefgereasdasdasidonefe fkefe'; val is 'asdasdasgerefgereasdasdasidonefe fkefe' равно False, хотя обе строки идентичны. В более общем смысле интернирование строк зависит от реализации и зависит от того, как были определены строки: см. val = '50' vs val = str(50) - person Davidmh; 20.10.2020

Из рекомендаций по программированию, PEP 8:

Сравнения с синглтонами, такими как None, всегда должны выполняться с помощью is или is not, а не операторов равенства.

Кроме того, остерегайтесь писать if x, когда на самом деле имеете в виду if x is not None — например, при проверке того, было ли переменной или аргументу, который по умолчанию равен None, присвоено какое-либо другое значение. Другое значение может иметь тип (например, контейнер), который может быть ложным в логическом контексте!

PEP 8 является важным чтением для любого программиста Python.

person Johnsyweb    schedule 19.10.2010

Лучше всего с такими вопросами посмотреть, что именно делает python. Модуль dis невероятно информативен:

>>> import dis
>>> dis.dis("val != None")
  1           0 LOAD_NAME                0 (val)
              2 LOAD_CONST               0 (None)
              4 COMPARE_OP               3 (!=)
              6 RETURN_VALUE
>>> dis.dis("not (val is None)")
  1           0 LOAD_NAME                0 (val)
              2 LOAD_CONST               0 (None)
              4 COMPARE_OP               9 (is not)
              6 RETURN_VALUE
>>> dis.dis("val is not None")
  1           0 LOAD_NAME                0 (val)
              2 LOAD_CONST               0 (None)
              4 COMPARE_OP               9 (is not)
              6 RETURN_VALUE

Обратите внимание, что последние два случая сводятся к одной и той же последовательности операций: Python читает not (val is None) и использует is not оператор. Первый использует оператор != при сравнении с None.

Как указано в других ответах, использование != при сравнении с None - плохая идея.

person SheetJS    schedule 20.10.2013
comment
В чем разница между compare_op 9 и 3? - person evolvedmicrobe; 10.01.2017
comment
@evolvedmicrobe Из dis doc (https://docs.python.org/3/library/dis.html), COMPARE_OP выполняет логическую операцию, соответствующую кортежу dis.cmp_op = ('<', '<=', '==', '!=', '>', '>=', 'in', 'not in', 'is', 'is not', 'exception match', 'BAD'). Итак, COMPARE_OP 9 выполняет is not, а COMPARE_OP 3 выполняет !=. - person nivk; 20.11.2018

Любой из последних двух, поскольку val потенциально может иметь тип, который определяет __eq__() для возврата true при передаче None.

person Ignacio Vazquez-Abrams    schedule 19.10.2010
comment
Это довольно подлое __eq__() поведение, и я не подумал об этом. Хороший ответ для ловли углового случая. - person gotgenes; 19.10.2010