在编写一些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>:
与if <obj> is not None:
之间的区别以及为什么Python会关注我使用的内容吗?
我几乎总是使用前者,因为它更短,而不是双重否定,但经常在其他人的源代码中看到后者。
答案 0 :(得分:13)
if obj is not None
测试对象是否为None。 if obj
测试bool(obj)
是否为True。
有许多对象不是None但是bool(obj)
为False:例如,空列表,空字典,空集,空字符串。 。
如果要测试对象是否为None,请使用if obj is not None
。仅当您要测试一般“虚假”时才使用if obj
- 其定义与对象有关。
答案 1 :(得分:8)
这个答案专门针对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"
答案 2 :(得分:1)
有关完整说明,请考虑以下示例:
>>> 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()
发生了什么?我们来看看。正在运行dis.dis(is_truthy)
会给您:
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
在ceval.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
,那么答案很简单。否则,解释器会通过调用object protocol中定义的PyObject_IsTrue()
来尝试找出对象是否为 truthy 。 code in object.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
也被视为虚假。然后检查number protocol,mapping protocol和sequence protocol等各种协议。否则该对象被认为是真的。
要将其包装起来:x
如果是True
则认为是真的,根据数字,映射或序列协议或某种其他类型的对象,则为真。如果您希望将对象评估为false,则可以通过实现任何所述协议来执行此操作,请参阅提供的链接。
与None
中的if x is None
相比,是一种明确的比较。上述逻辑不适用。
答案 3 :(得分:0)
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
为0,无,空列表或空字符串,则条件x
下的语句将不执行。另一方面,if x is not None
仅在x
完全None
时适用。