【通过Cpython3.9源码看看列表到底是咋回事】

在这里插入图片描述

列表结构

typedef struct {
    PyObject_VAR_HEAD
    /* Vector of pointers to list elements.  list[0] is ob_item[0], etc. */
    PyObject **ob_item;

    /* ob_item contains space for 'allocated' elements.  The number
     * currently in use is ob_size.
     * Invariants:
     *     0 <= ob_size <= allocated
     *     len(list) == ob_size
     *     ob_item == NULL implies ob_size == allocated == 0
     * list.sort() temporarily sets allocated to -1 to detect mutations.
     *
     * Items must normally not be NULL, except during construction when
     * the list is not yet visible outside the function that builds it.
     */
    Py_ssize_t allocated;
} PyListObject;

其中定义了一个名为PyListObject的结构体。下面是这个结构体中的各个成员变量的详细解释:

  1. PyObject_VAR_HEAD:这是一个宏定义,它定义了一个PyObject对象的头部。在PyListObject结构体中,这个宏定义的作用是将PyListObject与PyObject对象关联起来,以便在Python解释器中进行类型检查和垃圾回收等操作。这个宏定义包含了以下内容:

    PyObject ob_base;
    Py_ssize_t ob_size;
    

    其中,PyObject是一个C语言结构体,表示Python对象的基础部分。ob_size是一个Py_ssize_t类型的整数,用于表示对象的大小。当使用PyObject_VAR_HEAD宏定义一个对象的头部时,ob_size会被设置为0这表示这个对象的大小是变长的,可以动态地分配内存。在Python中,许多对象,例如列表、元组、字典等,都是变长的,因此通常会使用PyObject_VAR_HEAD来定义这些对象的头部。这个宏定义的作用是将Python对象的头部和实际的数据结构关联起来,以便在Python解释器中进行类型检查和垃圾回收等操作。

  2. PyObject **ob_item:这是一个指针数组,用于存储Python列表中的元素。列表中的第一个元素存储在ob_item[0]中,以此类推。这个数组的大小由成员变量allocated决定。

  3. Py_ssize_t allocated:这是一个整型变量,表示ob_item数组中分配的内存空间大小。allocated的值必须大于等于列表中实际元素的个数ob_size。如果allocated的值为负数,则表示列表已被排序或已发生了变异,需要进行特殊处理。在Python的实现中,当对一个列表进行排序或者其他改变列表结构的操作时,为了避免出现潜在的问题,Python会对这个列表的allocated成员变量进行一个特殊的标记,将其值设置为负数,表示列表已经被排序或发生了变异。这个标记的作用是在随后的操作中,比如插入或删除元素时,检查这个列表是否已经被修改,如果是,则需要重新分配内存空间,并将allocated的值设置为正数。这个特殊处理的作用是保证了列表在被修改时的安全性,同时也保证了内存分配的效率。在Python中,列表的内存分配是动态的,如果不进行特殊处理,可能会出现内存分配过多或者过少的情况,导致程序效率降低。因此,为了保证Python程序的高效性和正确性,对于列表的修改操作,Python实现中会进行特殊处理,以确保内存的合理分配和程序的正确性。

  4. Invariants:这是一组不变式,用于描述列表ob_item和PyListObject结构体中的其他成员变量之间的关系。具体来说,这些不变式包括:

    • 0 <= ob_size <= allocated:ob_size表示列表中实际元素的个数,allocated表示ob_item数组的大小。这个不变式表明,ob_size必须小于等于allocated,并且ob_size和allocated必须都是非负数。
    • len(list) == ob_size:这个不变式表示列表的长度必须等于ob_size。
    • ob_item == NULL implies ob_size == allocated == 0:如果ob_item为NULL,则表示列表为空。此时,ob_size和allocated都必须为0。
    • list.sort() temporarily sets allocated to -1 to detect mutations.:当对列表进行排序操作时,allocated的值会被暂时设置为-1,以便检测列表是否发生了变异。
  5. Items must normally not be NULL, except during construction when the list is not yet visible outside the function that builds it.:在大多数情况下,列表中的元素不能为NULL。但是,在构建列表的函数中,如果列表还没有被返回并且在函数外部不可见,那么列表中的元素可以为NULL。

列表初始化

static int
list___init___impl(PyListObject *self, PyObject *iterable)
/*[clinic end generated code: output=0f3c21379d01de48 input=b3f3fe7206af8f6b]*/
{
    /* Verify list invariants established by PyType_GenericAlloc() */
    assert(0 <= Py_SIZE(self));
    assert(Py_SIZE(self) <= self->allocated || self->allocated == -1);
    assert(self->ob_item != NULL ||
           self->allocated == 0 || self->allocated == -1);

    /* Empty previous contents */
    if (self->ob_item != NULL) {
        (void)_list_clear(self);
    }
    if (iterable != NULL) {
        if (_PyObject_HasLen(iterable)) {
            Py_ssize_t iter_len = PyObject_Size(iterable);
            if (iter_len == -1) {
                if (!PyErr_ExceptionMatches(PyExc_TypeError)) {
                    return -1;
                }
                PyErr_Clear();
            }
            if (iter_len > 0 && self->ob_item == NULL
                && list_preallocate_exact(self, iter_len)) {
                return -1;
            }
        }
        PyObject *rv = list_extend(self, iterable);
        if (rv == NULL)
            return -1;
        Py_DECREF(rv);
    }
    return 0;
}

用于初始化Python列表对象。下面是这个函数的具体实现:

  1. 首先,函数会检查列表的一些不变量,确保它们满足要求。这些不变量包括:列表中元素数量的范围在0到allocated之间,allocated是已分配的内存数量,ob_item指向列表元素的指针数组。如果不变量不满足要求,函数会抛出一个assertion failure。
  2. 如果列表中已经有元素了,则调用_list_clear函数清空列表中的所有元素。
  3. 如果传入的iterable参数不为空,则根据iterable的长度预分配足够的内存空间。如果预分配的内存空间失败,则返回-1表示操作失败。
  4. 调用list_extend函数,将iterable中的所有元素添加到列表中。如果操作失败,则返回-1表示操作失败。
  5. 返回0表示操作成功。

总体来说,该函数的作用是初始化Python列表对象。它首先检查列表的一些不变量,确保它们满足要求。然后,它清空列表中的所有元素,并根据传入的iterable参数预分配足够的内存空间。最后,它调用list_extend函数,将iterable中的所有元素添加到列表中。

列表插入操作

int
PyList_Insert(PyObject *op, Py_ssize_t where, PyObject *newitem)
{
    if (!PyList_Check(op)) {
        PyErr_BadInternalCall();
        return -1;
    }
    return ins1((PyListObject *)op, where, newitem);
}
  1. 首先检查op是否为Python列表类型。如果op不是Python列表类型,则会抛出一个PyErr_BadInternalCall异常,并返回-1表示操作失败。
  2. 调用ins1函数,在指定位置where处将newitem插入到列表op中。
  3. 返回ins1函数的返回值,表示操作是否成功。
static int
ins1(PyListObject *self, Py_ssize_t where, PyObject *v)
{
    Py_ssize_t i, n = Py_SIZE(self);
    PyObject **items;
    if (v == NULL) {
        PyErr_BadInternalCall();
        return -1;
    }
    if (n == PY_SSIZE_T_MAX) {
        PyErr_SetString(PyExc_OverflowError,
            "cannot add more objects to list");
        return -1;
    }

    if (list_resize(self, n+1) < 0)
        return -1;

    if (where < 0) {
        where += n;
        if (where < 0)
            where = 0;
    }
    if (where > n)
        where = n;
    items = self->ob_item;
    for (i = n; --i >= where; )
        items[i+1] = items[i];
    Py_INCREF(v);
    items[where] = v;
    return 0;
}
  1. 首先获取列表的当前长度n,然后检查要插入的元素v是否为NULL。如果v为NULL,则表示出现了内部调用错误,会抛出一个PyErr_BadInternalCall异常,并返回-1表示操作失败。
  2. 如果列表已经达到了最大长度,那么插入操作无法进行,会抛出一个PyExc_OverflowError异常,并返回-1表示操作失败。
  3. 调用list_resize函数扩展列表的大小,使其能够容纳一个新的元素。如果扩展失败,会返回-1表示操作失败。
  4. 根据插入位置where的值,更新其值。如果where小于0,则表示从列表末尾开始往前数,因此需要计算出正确的位置。如果where大于n,则表示要在列表末尾插入元素,因此需要将where的值设置为n。
  5. 定义一个名为items的指针数组,用于存储列表中的元素。
  6. 使用for循环,将从where位置开始的所有元素往后移动一个位置,以腾出一个位置用于插入新元素。
  7. 使用Py_INCREF宏对新元素进行引用计数,然后将其插入到列表的where位置。
  8. 返回0表示插入操作成功。

总体来说,这个函数的作用是在Python列表中插入一个新元素。它首先检查输入参数是否正确,然后通过调用list_resize函数扩展列表的大小,并将所有元素往后移动一个位置,以腾出一个位置用于插入新元素。最后,使用Py_INCREF宏对新元素进行引用计数,并将其插入到指定位置。

列表删除操作

static PyObject *
list_remove(PyListObject *self, PyObject *value)
/*[clinic end generated code: output=f087e1951a5e30d1 input=2dc2ba5bb2fb1f82]*/
{
    Py_ssize_t i;

    for (i = 0; i < Py_SIZE(self); i++) {
        PyObject *obj = self->ob_item[i];
        Py_INCREF(obj);
        int cmp = PyObject_RichCompareBool(obj, value, Py_EQ);
        Py_DECREF(obj);
        if (cmp > 0) {
            if (list_ass_slice(self, i, i+1,
                               (PyObject *)NULL) == 0)
                Py_RETURN_NONE;
            return NULL;
        }
        else if (cmp < 0)
            return NULL;
    }
    PyErr_SetString(PyExc_ValueError, "list.remove(x): x not in list");
    return NULL;
}

这是一个名为list_remove的函数,用于从Python列表中移除指定的元素。下面是这个函数的具体实现:

  1. 定义一个名为i的Py_ssize_t类型变量,用于遍历列表中的所有元素。
  2. 使用for循环遍历列表中的所有元素。在每次循环中,从列表中获取一个元素obj,并使用PyObject_RichCompareBool函数将这个元素与待移除元素value进行比较。
  3. 如果比较的结果为1,则表示找到了待移除元素。此时,调用list_ass_slice函数,将列表中从i到i+1的元素删除,并返回Py_RETURN_NONE表示移除操作成功。
  4. 如果比较的结果为-1,则表示出现了异常。此时,直接返回NULL表示操作失败。
  5. 如果比较的结果为0,则继续遍历下一个元素。
  6. 如果在整个循环中都没有找到待移除元素,则会抛出一个PyExc_ValueError异常,并返回NULL表示操作失败。

总体来说,list_remove函数的作用是从Python列表中移除指定的元素。它遍历列表中的所有元素,将每个元素与待移除元素进行比较,找到待移除元素后调用list_ass_slice函数将其从列表中删除。如果整个列表中都没有待移除元素,则会抛出一个异常表示操作失败。

列表修改

#define PyList_SET_ITEM(op, i, v) (_PyList_CAST(op)->ob_item[i] = (v))

在 CPython 中,#define PyList_SET_ITEM(op, i, v) (_PyList_CAST(op)->ob_item[i] = (v)) 是一个宏定义,用于修改 Python 列表对象中指定索引位置的元素。

这个宏定义中包含了三个参数:

  1. op:要修改的 Python 列表对象。
  2. i:要修改的元素的索引位置。
  3. v:新的元素值。

在宏定义中,使用了 _PyList_CAST 函数将 op 转换成了 PyListObject* 类型,从而可以使用 ob_item 成员来访问列表对象的元素。具体实现中,宏定义将指定索引位置 i 处的元素值设置为新的元素值 v,实现了 Python 列表对象中指定元素的修改。

列表查找

#define PyList_GET_ITEM(op, i) (_PyList_CAST(op)->ob_item[i])

在 CPython 中,#define PyList_GET_ITEM(op, i) (_PyList_CAST(op)->ob_item[i]) 是一个宏定义,用于获取 Python 列表对象中指定索引位置的元素。

这个宏定义中包含了两个参数:

  1. op:要访问的 Python 列表对象。
  2. i:要访问的元素的索引位置。

在宏定义中,使用了 _PyList_CAST 函数将 op 转换成了 PyListObject* 类型,从而可以使用 ob_item 成员来访问列表对象的元素。具体实现中,宏定义返回了指定索引位置 i 处的元素值,实现了 Python 列表对象中指定元素的访问。

列表比较

static PyObject *
list_richcompare(PyObject *v, PyObject *w, int op)
{
    PyListObject *vl, *wl;
    Py_ssize_t i;

    if (!PyList_Check(v) || !PyList_Check(w))
        Py_RETURN_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 */
        if (op == Py_EQ)
            Py_RETURN_FALSE;
        else
            Py_RETURN_TRUE;
    }

    /* Search for the first index where items are different */
    for (i = 0; i < Py_SIZE(vl) && i < Py_SIZE(wl); i++) {
        PyObject *vitem = vl->ob_item[i];
        PyObject *witem = wl->ob_item[i];
        if (vitem == witem) {
            continue;
        }

        Py_INCREF(vitem);
        Py_INCREF(witem);
        int k = PyObject_RichCompareBool(vitem, witem, Py_EQ);
        Py_DECREF(vitem);
        Py_DECREF(witem);
        if (k < 0)
            return NULL;
        if (!k)
            break;
    }

    if (i >= Py_SIZE(vl) || i >= Py_SIZE(wl)) {
        /* No more items to compare -- compare sizes */
        Py_RETURN_RICHCOMPARE(Py_SIZE(vl), Py_SIZE(wl), op);
    }

    /* We have an item that differs -- shortcuts for EQ/NE */
    if (op == Py_EQ) {
        Py_RETURN_FALSE;
    }
    if (op == Py_NE) {
        Py_RETURN_TRUE;
    }

    /* Compare the final item again using the proper operator */
    return PyObject_RichCompare(vl->ob_item[i], wl->ob_item[i], op);
}

这是一个名为list_richcompare的函数,用于比较两个Python列表是否相等。下面是这个函数的具体实现:

  1. 定义两个PyListObject指针vl和wl,用于表示输入的两个Python列表。
  2. 检查v和w是否都是Python列表类型。如果其中一个不是Python列表类型,则返回Py_RETURN_NOTIMPLEMENTED。
  3. 将v和w强制转换为PyListObject类型,并将它们分别赋值给vl和wl。
  4. 如果两个列表的长度不同,并且比较操作是相等或不等操作,那么可以快速确定它们不相等,返回Py_RETURN_FALSE或Py_RETURN_TRUE。
  5. 使用for循环从前往后遍历列表vl和wl中的所有元素,找到第一个不相等的元素。
  6. 如果所有元素都相等,而且列表的长度相同,则返回Py_RETURN_RICHCOMPARE(Py_SIZE(vl), Py_SIZE(wl), op)。
  7. 如果找到了不相等的元素,则根据比较操作op返回一个新的PyObject对象,用于表示两个列表的比较结果。

总体来说,list_richcompare函数的作用是比较两个Python列表是否相等。它首先检查输入参数是否正确,然后遍历两个列表中的所有元素,找到第一个不相等的元素,并根据比较操作op返回一个新的PyObject对象,用于表示两个列表的比较结果。这个函数通常会被Python解释器调用,用于支持Python列表的比较操作

列表内置方法


static PyMethodDef list_methods[] = {
    {"__getitem__", (PyCFunction)list_subscript, METH_O|METH_COEXIST, "x.__getitem__(y) <==> x[y]"},
    LIST___REVERSED___METHODDEF
    LIST___SIZEOF___METHODDEF
    LIST_CLEAR_METHODDEF
    LIST_COPY_METHODDEF
    LIST_APPEND_METHODDEF
    LIST_INSERT_METHODDEF
    LIST_EXTEND_METHODDEF
    LIST_POP_METHODDEF
    LIST_REMOVE_METHODDEF
    LIST_INDEX_METHODDEF
    LIST_COUNT_METHODDEF
    LIST_REVERSE_METHODDEF
    LIST_SORT_METHODDEF
    {"__class_getitem__", (PyCFunction)Py_GenericAlias, METH_O|METH_CLASS, PyDoc_STR("See PEP 585")},
    {NULL,              NULL}           /* sentinel */
};

这是一个名为list_methods的数组,它包含了Python列表对象支持的所有方法。下面是这个数组的具体实现:

  1. "getitem"方法:用于根据索引返回列表中的元素。具体实现中,它调用list_subscript函数,并将列表对象和索引作为参数传入。
  2. LIST___REVERSED___METHODDEF:该宏定义一个名为"reversed"的方法,用于返回一个逆序迭代器。具体实现中,它调用list_reverse和PyObject_GetIter函数,返回一个新的逆序迭代器对象。
  3. LIST___SIZEOF___METHODDEF:该宏定义一个名为"sizeof"的方法,用于返回列表对象占用的内存大小。具体实现中,它调用list___sizeof___impl函数。
  4. LIST_CLEAR_METHODDEF:该宏定义一个名为"clear"的方法,用于清空列表中的所有元素。具体实现中,它调用list_clear函数。
  5. LIST_COPY_METHODDEF:该宏定义一个名为"copy"的方法,用于返回一个新的列表对象,包含原列表中的所有元素。具体实现中,它调用list_copy函数,返回一个新的列表对象。
  6. LIST_APPEND_METHODDEF:该宏定义一个名为"append"的方法,用于在列表的末尾添加一个元素。具体实现中,它调用list_append函数。
  7. LIST_INSERT_METHODDEF:该宏定义一个名为"insert"的方法,用于在列表中的指定位置插入一个元素。具体实现中,它调用list_insert函数。
  8. LIST_EXTEND_METHODDEF:该宏定义一个名为"extend"的方法,用于将一个可迭代对象中的所有元素添加到列表的末尾。具体实现中,它调用list_extend函数。
  9. LIST_POP_METHODDEF:该宏定义一个名为"pop"的方法,用于移除并返回列表中指定位置的元素。具体实现中,它调用list_pop函数。
  10. LIST_REMOVE_METHODDEF:该宏定义一个名为"remove"的方法,用于移除列表中第一个与指定值相等的元素。具体实现中,它调用list_remove函数。
  11. LIST_INDEX_METHODDEF:该宏定义一个名为"index"的方法,用于返回列表中第一个与指定值相等的元素的索引。具体实现中,它调用list_index函数。
  12. LIST_COUNT_METHODDEF:该宏定义一个名为"count"的方法,用于返回列表中与指定值相等的元素数量。具体实现中,它调用list_count函数。
  13. LIST_REVERSE_METHODDEF:该宏定义一个名为"reverse"的方法,用于将列表中的元素倒序排列。具体实现中,它调用list_reverse函数。
  14. LIST_SORT_METHODDEF:该宏定义一个名为"sort"的方法,用于将列表中的元素进行排序。具体实现中,它调用list_sort函数,该函数是一个静态函数,实现了Python列表对象的快速排序算法。具体实现中,它使用了经典的快速排序算法,将列表中的元素按照指定的比较函数进行排序。
  15. "class_getitem"方法:用于支持泛型类型。具体实现中,它调用Py_GenericAlias函数,并返回一个新的泛型别名对象。
  16. NULL:这是一个标志,用于标记方法列表的末尾。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/10529.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Matlab论文插图绘制模板第85期—模值赋色的箭头图

在之前的文章中&#xff0c;分享了Matlab箭头图的绘制模板&#xff1a; 进一步&#xff0c;如果我们想对每一个箭头赋上颜色&#xff0c;以更加直观地表示其模值的大小&#xff0c;该怎么操作呢&#xff1f; 那么&#xff0c;来看一下模值赋色的箭头图的绘制模板。 先来看一下…

老胡的周刊(第086期)

老胡的信息周刊[1]&#xff0c;记录这周我看到的有价值的信息&#xff0c;主要针对计算机领域&#xff0c;内容主题极大程度被我个人喜好主导。这个项目核心目的在于记录让自己有印象的信息做一个留存以及共享。&#x1f3af; 项目MochiDiffusion[2]在 MacOS 上运行原生的 Stab…

游戏解密之常见网络游戏同步方式分析

一、为什么需要有同步呢&#xff1f; 同步机制是用来维护游戏的一致性&#xff0c;通俗的说就是虚拟世界中的事实&#xff1b;比如在CF中&#xff0c;大家的PING都很高&#xff0c;A和B两个玩家同时发现了对方&#xff0c;并向对方开火&#xff0c;如果没有很好的同步机制&…

【学习笔记】滑动窗口

acwing.滑动窗口https://www.acwing.com/problem/content/156/ 给定一个大小为 n≤106≤106 的数组。 有一个大小为 k 的滑动窗口&#xff0c;它从数组的最左边移动到最右边。 你只能在窗口中看到 k 个数字。 每次滑动窗口向右移动一个位置。 以下是一个例子&#xff1a; …

【博学谷学习记录】超强总结,用心分享 | 架构师 MySql扩容学习总结

文章目录1. 停机方案2.停写方案3.日志方案4.双写方案&#xff08;中小型数据&#xff09;5.平滑2N方案&#xff08;大数据量&#xff09;1. 停机方案 发布公告 为了进行数据的重新拆分&#xff0c;在停止服务之前&#xff0c;我们需要提前通知用户&#xff0c;比如&#xff1a…

他98年的,我真的玩不过他...

现在的小年轻真的卷得过分了。前段时间我们公司来了个98年的&#xff0c;工作没两年&#xff0c;跳槽到我们公司起薪18K&#xff0c;都快接近我了。后来才知道人家是个卷王&#xff0c;从早干到晚就差搬张床到工位睡觉了。 最近和他聊了一次天&#xff0c;原来这位小老弟家里条…

MySQL 分布式数据库实现:无需修改代码,轻松实现分布式能力

这个项目做什么 ShardingSphere-Proxy&#xff0c;可以让用户像使用原生数据库一样使用 Apache ShardingSphere。 了解一项技术的开始&#xff0c;一般从官网开始。先来看一看官网对 ShardingSphere-Proxy 的定义是什么样的&#xff1a; 定位为透明化的数据库代理端&#xff…

springboot学习2

一、spring boot自动装配原理 pom.xml spring-boot-dependencies 核心依赖在父工程中 在写或者引入一些spring boot依赖的时候&#xff0c;不需要指定版本&#xff0c;因为有这些版本仓库启动器 <dependency><groupId>org.springframework.boot</groupId>&…

会画画的海龟,Python Turtle库详解(27)

小朋友们好&#xff0c;大朋友们好&#xff01; 我是猫妹&#xff0c;一名爱上Python编程的小学生。 欢迎和猫妹一起&#xff0c;趣味学Python。 今日主题 介绍下Python的turtle库&#xff0c;这是一个可以画画的库&#xff0c;非常适合小孩子在屏幕上画画。 先学习基础知…

第08章_面向对象编程(高级)

第08章_面向对象编程(高级) 讲师&#xff1a;尚硅谷-宋红康&#xff08;江湖人称&#xff1a;康师傅&#xff09; 官网&#xff1a;http://www.atguigu.com 本章专题与脉络 1. 关键字&#xff1a;static 回顾类中的实例变量&#xff08;即非static的成员变量&#xff09; c…

虚拟化技术:实现资源高效利用和灵活管理的利器

虚拟化技术是一种通过软件或硬件手段&#xff0c;将物理资源抽象化&#xff0c;从而创建虚拟资源的技术。这种技术可以应用于计算、存储、网络等领域&#xff0c;通过将物理资源划分为多个虚拟资源&#xff0c;使得多个应用程序或用户可以共享同一组物理资源&#xff0c;从而提…

Linux 进程管理之四大名捕

一、四大名捕 四大名捕&#xff0c;最初出现于温瑞安创作的武侠小说&#xff0c;是朝廷中正义力量诸葛小花的四大徒弟&#xff0c;四人各怀绝技&#xff0c;分别是轻功暗器高手 “无情”、内功卓越的高手“铁手”、腿功惊人的“追命” 和剑法一流的“冷血”。 本文四大名捕由…

关于电商商品数据API接口列表,你想知道的(详情页、Sku信息、商品描述、评论问答列表)

目录 一、商品数据API接口列表 二、商品详情数据API调用代码item_get 三、获取sku详细信息item_sku 四、获得淘宝商品评论item_review 五、数据说明文档 进入 一、商品数据API接口列表 二、商品详情数据API调用代码item_get <?php// 请求示例 url 默认请求参数已经URL…

集合-LinkedList

LinkedList LinkedList的概述 LinkedList的底层使用双向链表实现。 链表是一种线性数据结构&#xff0c;其中每个元素都是一个单独的对象&#xff0c;包含一个指向列表中下一个节点的引用。 它可以用于实现各种抽象数据类型&#xff0c;例如列表、堆栈、队列等。 LinkedLis…

Carla仿真二:Carla多视图切换代码详解

文章目录前言一、Carla多视图切换效果二、Camera安装坐标系1、Carla.Location2、Carla.Rotation三、接口及代码详解1、接口介绍2、生成上帝视图代码3、生成Camera视图代码四、完整代码前言 1、Carla提供了大量的Python API接口&#xff0c;用户可以通过查找文档实现各类功能&a…

无限制翻译软件-中英互译字数无限

翻译软件是我们工作及学习中必不可少的工具&#xff0c;然而许多翻译软件在使用时常常会出现字数限制的问题,这使得用户在处理长文本和大量文本时变得十分麻烦。如果你也遇到了类似的问题&#xff0c;那么哪个翻译软件不限制字数将为您带来全新的翻译体验。 以下是我们的哪个翻…

Vite打包后直接使用浏览器打开,显示空白问题

vite打包后&#xff0c;直接用浏览器打开显示空白 1.需求&#xff1a; 安卓webview等浏览器直接打开文件显示 2.原因 &#xff08;1&#xff09;资源路径错误&#xff1a; vite.config.js 配置 base: “./” &#xff08;在webpack中则配置publicPath: "./"即可…

ATTCK v12版本战术实战研究——提权(一)

一、概述 前几期文章中&#xff0c;我们中介绍ATT&CK 14项战术中提权战术&#xff08;一&#xff09;&#xff0c;包括提权前6项子技术。那么从前文中介绍的相关提权技术来开展测试&#xff0c;进行更深一步的分析。本文主要内容是介绍攻击者在运用提权技术时&#xff0c;…

算法 贪心2 || 122.买卖股票的最佳时机II 55. 跳跃游戏 45.跳跃游戏II

122.买卖股票的最佳时机II 如果想到其实最终利润是可以分解的&#xff0c;那么本题就很容易了&#xff01; 如何分解呢&#xff1f; 假如第0天买入&#xff0c;第3天卖出&#xff0c;那么利润为&#xff1a;prices[3] - prices[0]。 相当于(prices[3] - prices[2]) (prices[2…

【华为OD机试】1043 - 从单向链表中删除指定值的节点

文章目录一、题目&#x1f538;题目描述&#x1f538;输入输出&#x1f538;样例1&#x1f538;样例2二、代码参考作者&#xff1a;KJ.JK&#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &am…