Python中list的比較


在Python中,運行如下的代碼

nan = float("nan")
print nan == nan
print [nan] == [nan]

其輸出結果分別為False 和 True,於是決定去查看相關的代碼查找原因。

首先,float中nan在ieee標准中有約定,與任何值都不相等,所以主要需要確認的就是列表的比較規則。

static PyObject *
list_richcompare(PyObject *v, PyObject *w, int op)

list的比較使用的是list_richcompare函數,接收3個參數,待比較的兩個引用以及操作符

    if (!PyList_Check(v) || !PyList_Check(w)) {
        Py_INCREF(Py_NotImplemented);
        return Py_NotImplemented;
    }

    vl = (PyListObject *)v;
    wl = (PyListObject *)w;

首先檢查輸入的待比較的元素是否是列表,然后轉換指針的類型為列表

    if (Py_SIZE(vl) != Py_SIZE(wl) && (op == Py_EQ || op == Py_NE)) {
        /* Shortcut: if the lengths differ, the lists differ */
        PyObject *res;
        if (op == Py_EQ)
            res = Py_False;
        else
            res = Py_True;
        Py_INCREF(res);
        return res;
    }

對於,==和!=兩個操作符,如果兩個列表的大小不想等,則可以直接返回False或者True的結果,無須再進行其他比較。

    for (i = 0; i < Py_SIZE(vl) && i < Py_SIZE(wl); i++) {
        int k = PyObject_RichCompareBool(vl->ob_item[i],
                                         wl->ob_item[i], Py_EQ);
        if (k < 0)
            return NULL;
        if (!k)
            break;
    }

從頭開始比較列表的中元素,直到有一個列表遍歷完或者有不相等的情況則中止,搜索出第一個不相等的成員的索引值。

其中對於每個元素的比較,調用的是PyObject_RichCompareBool方法

    if (i >= Py_SIZE(vl) || i >= Py_SIZE(wl)) {
        /* No more items to compare -- compare sizes */
        Py_ssize_t vs = Py_SIZE(vl);
        Py_ssize_t ws = Py_SIZE(wl);
        int cmp;
        PyObject *res;
        switch (op) {
        case Py_LT: cmp = vs <  ws; break;
        case Py_LE: cmp = vs <= ws; break;
        case Py_EQ: cmp = vs == ws; break;
        case Py_NE: cmp = vs != ws; break;
        case Py_GT: cmp = vs >  ws; break;
        case Py_GE: cmp = vs >= ws; break;
        default: return NULL; /* cannot happen */
        }
        if (cmp)
            res = Py_True;
        else
            res = Py_False;
        Py_INCREF(res);
        return res;
    }

如果至少有一個列表遍歷結束,則所有比較過的元素都一致。

則哪個列表的尺寸長,那么該列表就大。如果兩個列表的尺寸相同,則這兩個列表就相等。只需針對不同的op,返回不同的結果即可。

    if (op == Py_EQ) {
        Py_INCREF(Py_False);
        return Py_False;
    }
    if (op == Py_NE) {
        Py_INCREF(Py_True);
        return Py_True;
    }

如果在兩列表的尺寸范圍內,找到了不相等的成員,就說明這兩個列表不相等,為==和!=提供捷徑。

return PyObject_RichCompare(vl->ob_item[i], wl->ob_item[i], op);

當op不為Py_EQ或Py_NE時,就將第一個不相等的成員的比較結果作為,這兩個列表的比較結果。

對於PyObject_RichCompareBool

/* Return -1 if error; 1 if v op w; 0 if not (v op w). */
int
PyObject_RichCompareBool(PyObject *v, PyObject *w, int op)
{
    PyObject *res;
    int ok;

    /* Quick result when objects are the same.
       Guarantees that identity implies equality. */
    if (v == w) {
        if (op == Py_EQ)
            return 1;
        else if (op == Py_NE)
            return 0;
    }

    res = PyObject_RichCompare(v, w, op);
    if (res == NULL)
        return -1;
    if (PyBool_Check(res))
        ok = (res == Py_True);
    else
        ok = PyObject_IsTrue(res);
    Py_DECREF(res);
    return ok;
}

在比較之前,會首先看兩個比較元素的引用地址,如果相同則視為相等。

所以nan在列表中比較時由於引用地址一樣,也會被視為相等。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM