Я бачив кілька прикладів такого коду:
if not someobj:
#do something
Але мені цікаво, чому б не зробити:
if someobj == None:
#do something
Чи є різниця? Чи має одна перевага перед іншою?
X != None?
Я бачив кілька прикладів такого коду:
if not someobj:
#do something
Але мені цікаво, чому б не зробити:
if someobj == None:
#do something
Чи є різниця? Чи має одна перевага перед іншою?
X != None?
Відповіді:
У першому тесті Python намагається перетворити об'єкт у boolзначення, якщо воно вже не є. Приблизно ми запитуємо об’єкт: ти значимий чи ні? Це робиться за допомогою наступного алгоритму:
Якщо об'єкт має __nonzero__спеціальний метод (як чисельні вбудовані модулі intта float), він називає цей метод. Він повинен або повертати boolзначення, яке потім використовується безпосередньо, або intзначення, яке вважається Falseрівним нулю.
В іншому випадку, якщо об'єкт має __len__спеціальний метод (як контейнер Модульні, list, dict, set, tuple, ...), він викликає цей метод, вважаючи контейнер , Falseякщо він порожній (довжина дорівнює нуль).
В іншому випадку об'єкт розглядається, Trueякщо тільки Noneв цьому випадку він не розглядається False.
У другому тесті об'єкт порівнюється на рівність None. Тут ми запитуємо об’єкт: "Чи дорівнює ви цій іншій цінності?" Це робиться за допомогою наступного алгоритму:
Якщо об'єкт має __eq__метод, він викликається, а повернене значення потім перетворюється у boolзначення і використовується для визначення результату if.
В іншому випадку, якщо об’єкт має __cmp__метод, він викликається. Ця функція повинна повертати intвказівний порядок двох об’єктів ( -1якщо self < other, 0якщо self == other, +1якщо self > other).
В іншому випадку об'єкт порівнюється за ідентичністю (тобто вони посилаються на той самий об'єкт, що може бути перевірений isоператором).
Можливий ще один тест за допомогою isоператора. Ми би запитували об’єкт: "Ти це конкретний об'єкт?"
Як правило, я б рекомендував використовувати перший тест з нечисловими значеннями, використовувати тест на рівність, коли потрібно порівнювати об'єкти одного характеру (два рядки, два числа, ...) і перевіряти ідентичність лише тоді, коли з використанням дозорних значень ( Noneмається на увазі не ініціалізовано для поля-члена для примірника, або при використанні методів getattrабо __getitem__).
Підводячи підсумок, ми маємо:
>>> class A(object):
... def __repr__(self):
... return 'A()'
... def __nonzero__(self):
... return False
>>> class B(object):
... def __repr__(self):
... return 'B()'
... def __len__(self):
... return 0
>>> class C(object):
... def __repr__(self):
... return 'C()'
... def __cmp__(self, other):
... return 0
>>> class D(object):
... def __repr__(self):
... return 'D()'
... def __eq__(self, other):
... return True
>>> for obj in ['', (), [], {}, 0, 0., A(), B(), C(), D(), None]:
... print '%4s: bool(obj) -> %5s, obj == None -> %5s, obj is None -> %5s' % \
... (repr(obj), bool(obj), obj == None, obj is None)
'': bool(obj) -> False, obj == None -> False, obj is None -> False
(): bool(obj) -> False, obj == None -> False, obj is None -> False
[]: bool(obj) -> False, obj == None -> False, obj is None -> False
{}: bool(obj) -> False, obj == None -> False, obj is None -> False
0: bool(obj) -> False, obj == None -> False, obj is None -> False
0.0: bool(obj) -> False, obj == None -> False, obj is None -> False
A(): bool(obj) -> False, obj == None -> False, obj is None -> False
B(): bool(obj) -> False, obj == None -> False, obj is None -> False
C(): bool(obj) -> True, obj == None -> True, obj is None -> False
D(): bool(obj) -> True, obj == None -> True, obj is None -> False
None: bool(obj) -> False, obj == None -> True, obj is None -> True
Це насправді обидва погані практики. Колись вважалося нормальним випадково ставитися до None і False як до подібних. Однак, оскільки Python 2.2 це не найкраща політика.
По-перше, коли ви робите тест if xабо if not xподібний тип, Python повинен неявно перетворюватися xна булевий. Правила boolфункції описують плот речей, які є помилковими; все інше - Правда. Якщо значення x було неправильно булевим для початку, це неявна конверсія насправді не є найяснішим способом сказати речі.
До Python 2.2 не було функції bool, тому було ще менш зрозуміло.
По-друге, не варто насправді тестувати == None. Ви повинні використовувати is Noneі is not None.
Див. PEP 8, Посібник зі стилю для Python Code .
- Comparisons to singletons like None should always be done with 'is' or 'is not', never the equality operators. Also, beware of writing "if x" when you really mean "if x is not None" -- e.g. when testing whether a variable or argument that defaults to None was set to some other value. The other value might have a type (such as a container) that could be false in a boolean context!
Скільки одинаків є? П'ять: None, True, False, NotImplementedі Ellipsis. Оскільки ви насправді не користуєтесь NotImplementedабо Ellipsis, і ви ніколи не скажете if x is True(адже це просто if xнабагато зрозуміліше), ви протестуєте лише коли-небудь None.
Тому що Noneце не єдине, що вважається помилковим.
if not False:
print "False is false."
if not 0:
print "0 is false."
if not []:
print "An empty list is false."
if not ():
print "An empty tuple is false."
if not {}:
print "An empty dict is false."
if not "":
print "An empty string is false."
False, 0, (), [], {}І ""все відрізняються від None, так що ваші два фрагменти коду НЕ еквівалентні.
Крім того, врахуйте наступне:
>>> False == 0
True
>>> False == ()
False
if object:- це не перевірка рівності. 0, (), [], None, {}І т.д. є все відрізняються один від одного, але всі вони оцінюють Брехня.
Це "магія" за виразами короткого замикання на кшталт:
foo = bar and spam or eggs
який є скороченим для:
if bar:
foo = spam
else:
foo = eggs
хоча вам справді слід написати:
foo = spam if bar else egg
PEP 8 - Посібник зі стилю для Python Code рекомендує використовувати є чи ні, якщо ви тестуєте на None-ness
- Comparisons to singletons like None should always be done with 'is' or 'is not', never the equality operators.
З іншого боку, якщо ви протестуєте більш ніж None-ness, вам слід скористатися булевим оператором.
Якщо ви запитаєте
if not spam:
print "Sorry. No SPAM."
__nonzero__ метод спам викликається. З посібника Python:
__nonzero__ ( само ) Закликається здійснити перевірку значення істинності та вбудований bool (); повинні повернути False або True, або їх цілочисельні еквіваленти 0 або 1. Коли цей метод не визначений, викликається __len __ (), якщо він визначений (див. нижче). Якщо клас не визначає ні __len __ (), ні __nonzero __ (), всі його екземпляри вважаються істинними.
Якщо ви запитаєте
if spam == None:
print "Sorry. No SPAM here either."
__eq__ метод спам викликається з аргументом None .
Для отримання додаткової інформації про можливості налаштування ознайомтесь із документацією Python за адресою https://docs.python.org/reference/datamodel.html#basic-customization
Ці два порівняння служать різним цілям. Перший перевіряє булеву вартість чогось, другий перевіряє на тотожність зі значенням None.
Відповідь "це залежить".
Я використовую перший приклад, якщо вважаю 0, "", [] та False (список не вичерпний) в цьому контексті еквівалентними "None".
Особисто я вибрав послідовний підхід у різних мовах: я роблю if (var)(або еквівалент) лише у тому випадку, якщо var оголошено булевим (або визначеним як таким, у C у нас немає конкретного типу). Я навіть префіксую ці змінні b((це було б bVarнасправді), щоб бути впевненим, що я випадково не використовую інший тип тут.
Мені не дуже подобається неявне кастинг до булевих, ще менше, коли є численні складні правила.
Звичайно, люди будуть не згодні. Деякі йдуть далі, я бачу if (bVar == true)в коді Java на своїй роботі (надто зайвий на мій смак!), Інші люблять занадто компактний синтаксис, що йде while (line = getNextLine())(занадто неоднозначно для мене).