簡體   English   中英

如果之間的區別 <obj> 而如果 <obj> 不是沒有

[英]Difference between if <obj> and if <obj> is not 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>:if <obj> is not None:之間的區別嗎?為什么Python會關心我使用的那個?

我幾乎總是使用前者,因為它更短並且不是雙負數,但經常在其他人的源代碼中看到后者。

if obj is not None測試對象是否為None。 if obj測試bool(obj)是否為True。

有許多對象不是None,而是bool(obj)為False:例如,一個空列表,一個空dict,一個空集,一個空字符串。

當您要測試if obj is not None時, if obj is not None則使用。 僅當要測試常規“假性”(定義取決於if obj才使用if obj

此答案專門針對FutureWarning。

首次編寫lxml時,如果lxml.etree._Element沒有子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的中心地位,並且擔心它會破壞很多現有代碼。

但是,為明確lxml.etree._Element並確保沒有lxml.etree._Element ,請不要使用if obj或如果該對象的類型為lxml.etree._Element if not obj使用if obj

而是,使用以下檢查之一:

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()發生了什么? 讓我們找出答案。 運行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_FALSEceval.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使用的對象已經是TrueFalse ,那么答案很簡單。 否則,解釋器將通過調用對象協議中定義的PyObject_IsTrue()來嘗試找出對象是否真實 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);
}

同樣,如果對象本身只是TrueFalse ,答案很簡單。 None一個也被認為是錯誤的。 然后檢查各種協議,例如數字協議映射協議序列協議 否則,該對象被認為是真實的。

總結一下:如果xTrue ,則將其視為true,根據數字,映射或序列協議或某種其他對象,則為True 如果希望對象的評估結果為false,則可以通過實現上述任何協議來實現,請參見提供的鏈接。

以比較Noneif 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!'

因此,例如,如果x為0,無,空列表或空字符串,則條件if x條件下的語句將執行。 另一方面, if x is not None則僅當x完全為None時才適用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM