Разница между if и if не равна None
при написании некоторого кода синтаксического анализа XML я получил предупреждение:
FutureWarning: The behavior of this method will change in future versions. Use specific 'len(elem)' or 'elem is not None' test instead.
где я использовал if <elem>:
чтобы проверить, Найдено ли значение для данного элемента.
может кто-нибудь уточнить разницу между if <obj>:
vs if <obj> is not None:
и почему Python заботится о том, что я использую?
я почти всегда использую первый, потому что он короче и не двойной отрицательный, но часто вижу последний в исходном коде других людей.
4 ответов
if obj is not None
проверьте, не является ли объект None. if obj
проверяет, является ли bool(obj)
- это правда.
есть много объектов, которые не являются ничем, но для которых bool(obj)
является False: например, пустой список, пустой дикт, пустой набор, пустая строка. . .
использовать if obj is not None
Если вы хотите проверить, не является ли объект None. Использовать if obj
только если вы хотите проверить общую "ложность" -определение которой зависит от объекта.
этот ответ касается FutureWarning конкретно.
когда lxml был впервые написан,lxml.etree._Element
считался фальшивым, если у него не было детей.
в результате, это может произойти:
>>> from lxml import etree
>>>
>>> root = etree.fromstring('<body><h1>Hello</h1></body>')
>>> print root
<Element body at 0x41d7680>
>>> print "root is not Falsey" if root else "root is Falsey"
<string>:1: FutureWarning: The behavior of this method will change in future versions. Use specific 'len(elem)' or 'elem is not None' test instead.
root is not Falsey
>>> # that's odd, a warning
>>> h1 = root.find('.//h1')
>>> print h1
<Element h1 at 0x41d7878>
>>> print "h1 is not Falsey" if h1 else "h1 is Falsey"
h1 is Falsey
>>> # huh, that is weird! In most of python, an object is rarely False
>>> # we did see a warning though, didn't we?
>>> # let's see how the different elements output
>>> print "root is not None" if root is not None else "root is None"
root is not None
>>> print "h1 is not None" if h1 is not None else "h1 is None"
h1 is not None
>>> print "Length of root is ", len(root)
Length of root is 1
>>> print "Length of h1 is ", len(h1)
Length of h1 is 0
>>> # now to look for something that's not there!
>>> h2 = root.find('.//h2')
>>> print h2
None
>>> print "h2 is not Falsey" if h2 else "h2 is Falsey"
h2 is Falsey
>>> print "h2 is not None" if h2 is not None else "h2 is None"
h2 is None
>>> print "Length of h2 is ", len(h2)
Traceback (most recent call last):
File "<console>", line 1, in <module>
TypeError: object of type 'NoneType' has no len()
Length of h2 is >>>
lxml обещает в течение 7+ лет, что это изменение произойдет (после прохождения нескольких версий), но никогда не выполнял угрозу, без сомнения, из-за того, как центральный lxml и боится, что он сломает много существующих код.
однако, чтобы быть явным и уверенным, что вы не ошибаетесь, никогда не используйте if obj
или if not obj
если этот объект имеет тип lxml.etree._Element
.
вместо этого используйте одну из следующих проверок:
obj = root.find('.//tag')
if obj is not None:
print "Object exists"
if obj is None:
print "Object does not exist/was not found"
if len(obj): # warning: if obj is None (no match found) TypeError
print "Object has children"
if not len(obj): # warning: if obj is None (no match found) TypeError
print "Object does not have children"
для полного объяснения рассмотрим следующий пример:
>>> import dis
>>> def is_truthy(x):
>>> return "Those sweed words!" if x else "All lies!"
>>> is_truthy(None)
'All lies!'
>>> is_truthy(1)
'Those sweed words!'
>>> is_truthy([])
'All lies!'
>>> is_truthy(object())
'Those sweed words!'
что происходит is_truthy()
? Давайте выясним. Бег!--5--> дает вам:
2 0 LOAD_FAST 0 (x)
3 POP_JUMP_IF_FALSE 10
6 LOAD_CONST 1 ('The pure word')
9 RETURN_VALUE
>> 10 LOAD_CONST 2 ('All lies!')
13 RETURN_VALUE
Как видите,x
помещается в стек, затем POP_JUMP_IF_FALSE
выполняется. Это займет прыжок, чтобы сначала нажать, а затем вернуть правильный ответ.
POP_JUMP_IF_FALSE
определена в Севол.c:
TARGET(POP_JUMP_IF_FALSE) {
PyObject *cond = POP();
int err;
if (cond == Py_True) {
Py_DECREF(cond);
FAST_DISPATCH();
}
if (cond == Py_False) {
Py_DECREF(cond);
JUMPTO(oparg);
FAST_DISPATCH();
}
err = PyObject_IsTrue(cond);
Py_DECREF(cond);
if (err > 0)
err = 0;
else if (err == 0)
JUMPTO(oparg);
else
goto error;
DISPATCH();
как вы можете видеть, если объект потребляется POP_JUMP_IF_FALSE
уже либо True
или False
ответ прост. В противном случае интерпретатор пытается выяснить, является ли объект истина по телефону PyObject_IsTrue()
, который определен в объект протоколом. The код в объект.c показывает вам, как именно это работает:
PyObject_IsTrue(PyObject *v)
{
Py_ssize_t res;
if (v == Py_True)
return 1;
if (v == Py_False)
return 0;
if (v == Py_None)
return 0;
else if (v->ob_type->tp_as_number != NULL &&
v->ob_type->tp_as_number->nb_bool != NULL)
res = (*v->ob_type->tp_as_number->nb_bool)(v);
else if (v->ob_type->tp_as_mapping != NULL &&
v->ob_type->tp_as_mapping->mp_length != NULL)
res = (*v->ob_type->tp_as_mapping->mp_length)(v);
else if (v->ob_type->tp_as_sequence != NULL &&
v->ob_type->tp_as_sequence->sq_length != NULL)
res = (*v->ob_type->tp_as_sequence->sq_length)(v);
else
return 1;
/* if it is negative, it should be either -1 or -2 */
return (res > 0) ? 1 : Py_SAFE_DOWNCAST(res, Py_ssize_t, int);
}
опять же, если объект-это просто True
или False
сами, ответ прост. None
также считается ложным. Затем различные протоколы, такие как номер протокола на протокол сопоставления и протокол последовательности есть. В противном случае объект считается истинным.
в результате: x
считается истинным, если это True
, true в соответствии с номером, отображением или протоколом последовательности или каким-либо другим типом объекта. Если вы хотите, чтобы ваш объект оценивался как false, вы можете сделать это, реализовав любой из указанных протоколов, см. предоставленные ссылки.
по сравнению с None
как и в if x is None
- это явное сравнение. Приведенная выше Логика неприменима.
поведение if x
Это интересно:
In [1]: def truthy(x):
...: if x:
...: return 'Truthy!'
...: else:
...: return 'Not truthy!'
...:
In [2]: truthy(True)
Out[2]: 'Truthy!'
In [3]: truthy(False)
Out[3]: 'Not truthy!'
In [4]: truthy(0)
Out[4]: 'Not truthy!'
In [5]: truthy(1)
Out[5]: 'Truthy!'
In [6]: truthy(None)
Out[6]: 'Not truthy!'
In [7]: truthy([])
Out[7]: 'Not truthy!'
In [8]: truthy('')
Out[8]: 'Not truthy!'
Итак, например, операторы под условным if x
будет не выполняется, если x
равно 0, None, пустой список или пустая строка. С другой стороны!--4--> будет применяться только тогда, когда x
- это именно None
.