• 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在列表中比较时由于引用地址一样,也会被视为相等。

  • 相关阅读:
    MFC总结
    工作项目总结
    关于多线程使用sqlite3的问题
    vs调试时,不显示局部变量
    oracle和mysql互相迁移
    oracle如何设置ip访问数据库
    win7 安装oracle 11g图文步骤
    Mybatis传参
    别纠结mybatis啦,赶紧来瞅瞅吧
    程序员和管理常用的网站地址
  • 原文地址:https://www.cnblogs.com/ruizhang3/p/6855015.html
Copyright © 2020-2023  润新知