Відповіді:
Заява
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 Usec на цикл, тоді if object() is not None: passяк ~ 0,135 Usec. У будь-якому випадку, ви не повинні використовувати продуктивність для вибору між цими двома, а краще дивитися на відмінності в тому, як вони працюють, оскільки вони не є рівнозначними .
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, завжди слід робити з "є" або "ні", ніколи оператори рівності .
Крім того, будьте обережні, щоб написати "if x", якщо ви дійсно маєте на увазі "якщо x - немає None" - наприклад, під час тестування, чи змінна або аргумент, який за замовчуванням не був встановлений на якесь інше значення. Інше значення може мати тип (наприклад, контейнер), який може бути помилковим у булевому контексті!
None, а просто перевірка цінності правди. У цьому випадку if A:здається більш ефективним (наприклад dis.dis(), є додаткові кроки завантаження вбудованого Noneта порівняння з if A is not None:, jump_ifв іншому випадку є лише a ).
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
Багато функцій повертає Жодну, якщо немає відповідних результатів. Наприклад, запит SQLAlchemy.first() повертає 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 або string interning). Я не впевнений, що я слідкую за тим, що ти маєш на увазі.
Noneповодиться інакше , ніж intабо strз - за інтернування. Суть в тому , що isі ==перевіряють різні речі; перший перевіряє адресу пам'яті, другий перевіряє вміст адрес пам'яті.
if A: виявиться помилковим, якщо A дорівнює 0, False, порожній рядок, порожній список або None, що може призвести до небажаних результатів.
Більшість посібників, яких я бачив, пропонують використовувати
якщо:
якщо у вас немає причини бути більш конкретним.
Є деякі незначні відмінності. Є інші значення, крім None, які повертають помилкові, наприклад, порожні списки або 0, тому подумайте, для чого це ви насправді тестуєте.
Ніхто не є спеціальним значенням у Python, яке зазвичай позначає неініціалізовану змінну. Щоб перевірити, чи не має A таке конкретне значення, ви використовуєте:
if A is not None
Значення Фальсі - це особливий клас об’єктів у Python (наприклад, false, []). Щоб перевірити, чи є фальсифікатом A:
if not A
Таким чином, два вирази не однакові, і вам краще не ставитися до них як до синонімів.
PS None також не є фальсією, тому перший вираз передбачає другий. Але друга охоплює інші значення фальси, крім None. Тепер ... якщо ви можете бути впевнені, що ви не можете мати інших значень фальси, крім 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'>
пітон> = 2,6,
якщо ми пишемо такі як
if A:
буде генерувати попередження як,
FutureWarning: У наступних версіях поведінка цього методу зміниться. Використовуйте певний тест 'len (elem)' або 'elem is no None'.
Тож ми можемо використовувати
if A is not None:
A is not Noneшвидше, оскільки роботи тут набагато менше