Ответы:
Заявление
if A:
будет вызывать A.__nonzero__()(см. документацию по именам специальных методов ) и использовать возвращаемое значение этой функции. Вот резюме:
object.__nonzero__(self)Вызывается для выполнения проверки истинности значения и встроенной операции
bool(); должен вернутьFalseилиTrue, или их целочисленные эквиваленты0или1. Когда этот метод не определен,__len__()вызывается, если он определен, и объект считается истинным, если его результат ненулевой. Если класс не определяет ни то,__len__()ни другое__nonzero__(), все его экземпляры считаются истинными.
С другой стороны,
if A is not None:
сравнивает только ссылку Aс тем, Noneчтобы увидеть, является ли это то же самое или нет.
if object(): pass~ 0,130 мксек на цикл, а if object() is not None: pass~ 0,135 мксек. В любом случае, вам не следует использовать производительность, чтобы выбирать между этими двумя, а скорее смотреть на различия в том, как они работают, поскольку они не эквивалентны .
if A is not Noneкажется, медленнее, потому что это сравнение, и ему нужно загрузить встроенный синглтон Noneв качестве промежуточного шага для сравнения A(взгляните на dis.dis()). Поправь меня, если я ошибаюсь, но, if A:кажется, это более эффективно, как только ты действительно хочешь проверить ценность истины, а не Noneличность.
python -m timeit -s"a=0" "if a: pass" "else: pass"быстрее, python -m timeit -s"a=0" "if a is None: pass" "else: pass"но python -m timeit -s"a=1" "if a: pass" "else: pass"медленнее. Может зависеть от платформы, посмотреть, если вы получите те же результаты
is Noneтест был действительно самым медленным для меня. В pypy они все измерены абсолютно одинаково :)
Как написано в PEP8 :
Сравнения с синглетами, такими как None, всегда следует выполнять с помощью «is» или «is not», а не операторов равенства .
Кроме того, остерегайтесь писать «если x», когда вы действительно имеете в виду «если x не None» - например, при проверке, было ли для переменной или аргумента, которое по умолчанию None, установлено какое-то другое значение. Другое значение может иметь тип (например, контейнер), который может быть ложным в логическом контексте!
None, а просто проверкой истинности. В этом случае if A:кажется более эффективным (принять dis.dis(), есть дополнительные шаги загрузки встроенного Noneи сравнения, с if A is not None:, в то время как есть только jump_ifв другом случае).
if x: #x is treated True except for all empty data types [],{},(),'',0 False, and None
так что это не то же самое, что
if x is not None # which works only on None
Многие функции возвращают None, если нет подходящих результатов. Например, .first()метод запроса SQLAlchemy возвращает None, если в результате не было строк. Предположим, вы выбираете значение, которое может возвращать 0, и вам необходимо знать, действительно ли оно равно 0 или запрос не дал результатов вообще.
Распространенной идиомой является присвоение необязательному аргументу функции или метода значения по умолчанию None, а затем проверка значения None, чтобы убедиться, что оно указано. Например:
def spam(eggs=None):
if eggs is None:
eggs = retrievefromconfigfile()
сравните это с:
def spam(eggs=None):
if not eggs:
eggs = retrievefromconfigfile()
В последнем случае, что произойдет, если вы позвоните spam(0)или spam([])? Функция (неправильно) обнаружит, что вы не передали значение, eggsи вычислит значение по умолчанию для вас. Это, вероятно, не то, что вы хотите.
Или представьте себе такой метод, как «вернуть список транзакций для данного аккаунта». Если аккаунт не существует, он может вернуть None. Это отличается от возврата пустого списка (что означало бы, что «эта учетная запись существует, но не записала транзакции).
Наконец, вернемся к материалам базы данных. Существует большая разница между NULL и пустой строкой. Пустая строка обычно говорит: «здесь есть значение, а это значение вообще ничего». NULL говорит: «это значение не было введено».
В каждом из этих случаев вы бы хотели использовать if A is None. Вы проверяете конкретное значение - None - не просто «любое значение, приведенное к False».
Они делают разные вещи .
Приведенные ниже проверки , если А имеет ничего , кроме значений False, [], None, ''и 0. Проверяет значение А.
if A:
Ниже проверяется, является ли объект A отличным от None. Он проверяет и сравнивает ссылку (адрес памяти) A и None.
if A is not None:
ОБНОВЛЕНИЕ: дальнейшее объяснение
Часто кажется, что они делают одно и то же, поэтому многие люди используют их взаимозаменяемо - это действительно плохая идея. Причина, по которой эти два результата дают одни и те же, много раз по чистой случайности из-за оптимизаций интерпретатора / компилятора, таких как интернирование или что-то еще.
С учетом этих оптимизаций целые и строки одного и того же значения в конечном итоге используют одно и то же пространство памяти. Это, вероятно, объясняет, почему две отдельные строки действуют так, как если бы они были одинаковыми.
> a = 'test'
> b = 'test'
> a is b
True
> a == b
True
Другие вещи не ведут себя так же, хотя ..
> a = []
> b = []
> a is b
False
> a == b
True
У двух списков явно есть своя память. Удивительно, но кортежи ведут себя как строки.
> a = ()
> b = ()
> a is b
True
> a == b
True
Вероятно, это потому, что кортежи гарантированно не изменятся, поэтому имеет смысл повторно использовать одну и ту же память.
Суть в том, что нельзя полагаться на совпадения . То, что это крякает как утка, не означает, что это утка. Используйте isи в ==зависимости от того, что вы действительно хотите проверить. Эти вещи трудно отладить, так isкак они читаются как проза, и мы часто просто просматриваем их.
Noneэто синглтон, это не деталь реализации (в отличие от int или интернирования строк). Я не уверен, что понимаю, что вы имеете в виду.
Noneведет себя иначе, чем intили strиз-за интернирования. Моя точка зрения в том, что isи ==проверяют разные вещи; первый проверяет адрес памяти, второй проверяет содержимое адресов памяти.
if A: будет иметь значение false, если A равно 0, False, пустая строка, пустой список или None, что может привести к нежелательным результатам.
Большинство руководств, которые я видел, предлагают вам использовать
если:
если у вас нет причин быть более конкретными.
Есть небольшие отличия. Существуют значения, отличные от None, которые возвращают False, например, пустые списки или 0, поэтому подумайте, что именно вы проверяете.
None - это специальное значение в Python, которое обычно обозначает неинициализированную переменную. Чтобы проверить, нет ли у A конкретного значения, которое вы используете:
if A is not None
Значения Falsey - это особый класс объектов в Python (например, false, []). Чтобы проверить, является ли A ложным, используйте:
if not A
Таким образом, эти два выражения не совпадают, и вам лучше не рассматривать их как синонимы.
PS Нет, это тоже фальшивка, поэтому первое выражение подразумевает второе. Но вторая охватывает другие значения фальши, кроме None. Теперь ... если вы можете быть уверены, что у вас не может быть других значений Falsey, кроме None в A, то вы можете заменить первое выражение вторым.
Это зависит от контекста.
Я использую, if A:когда я ожидаю, Aчто будет какая-то коллекция, и я хочу выполнить блок, только если коллекция не пустая. Это позволяет вызывающей стороне передавать любую коллекцию с хорошим поведением, пустую или нет, и делать так, как я ожидаю. Это также позволяет Noneи Falseподавлять выполнение блока, что иногда удобно для вызова кода.
OTOH, если я ожидаю, Aчто какой-то совершенно произвольный объект, но он мог бы быть по умолчанию None, то я всегда использую if A is not None, так как вызывающий код мог преднамеренно передать ссылку на пустую коллекцию, пустую строку или 0-значный числовой тип, или логический False, или некоторый экземпляр класса, который оказывается ложным в логическом контексте.
И с другой стороны, если я ожидаю, что Aэто будет более конкретная вещь (например, экземпляр класса, для которого я собираюсь вызывать методы), но его можно было бы использовать по умолчанию None, и я считаю, что логическое преобразование по умолчанию является свойство класса, которое я не прочь применить на всех подклассах, тогда я просто буду использовать, if A:чтобы избавить мои пальцы от ужасного бремени ввода дополнительных 12 символов.
Я создал файл с именем test.pyи запустил его на интерпретаторе. Вы можете изменить то, что хотите, чтобы точно проверить, как идут дела за кулисами.
import dis
def func1():
matchesIterator = None
if matchesIterator:
print( "On if." );
def func2():
matchesIterator = None
if matchesIterator is not None:
print( "On if." );
print( "\nFunction 1" );
dis.dis(func1)
print( "\nFunction 2" );
dis.dis(func2)
В этом отличие ассемблера:

Источник:
>>> import importlib
>>> reload( test )
Function 1
6 0 LOAD_CONST 0 (None)
3 STORE_FAST 0 (matchesIterator)
8 6 LOAD_FAST 0 (matchesIterator)
9 POP_JUMP_IF_FALSE 20
10 12 LOAD_CONST 1 ('On if.')
15 PRINT_ITEM
16 PRINT_NEWLINE
17 JUMP_FORWARD 0 (to 20)
>> 20 LOAD_CONST 0 (None)
23 RETURN_VALUE
Function 2
14 0 LOAD_CONST 0 (None)
3 STORE_FAST 0 (matchesIterator)
16 6 LOAD_FAST 0 (matchesIterator)
9 LOAD_CONST 0 (None)
12 COMPARE_OP 9 (is not)
15 POP_JUMP_IF_FALSE 26
18 18 LOAD_CONST 1 ('On if.')
21 PRINT_ITEM
22 PRINT_NEWLINE
23 JUMP_FORWARD 0 (to 26)
>> 26 LOAD_CONST 0 (None)
29 RETURN_VALUE
<module 'test' from 'test.py'>
python> = 2.6,
если мы напишем такие как
if A:
будет генерировать предупреждение как,
FutureWarning: поведение этого метода будет меняться в будущих версиях. Вместо этого используйте специальный тест «len (elem)» или «elem is None».
Таким образом, мы можем использовать
if A is not None:
A is not Noneбыстрее, так как работы намного меньше