CPython:有没有任何方法可以将PyObject作为一个序列遍历,而不必随后创建和销毁对象?

2024-05-15 23:54:28 发布

您现在位置:Python中文网/ 问答频道 /正文

为了创建一个充当序列的PyObject,我只在PyTypeObject的变量tp_as_sequence的槽sq_item中添加了一个函数。你知道吗

这是我的sq_item函数:

static PyObject *py_myseq__sq_item(PyMySeq *self, unsigned int keynum)
{
    if (keynum < 0) keynum += self->len; /* ex.:>>> my_seq[-1] */
    if (keynum >= 0 && keynum < self->len) {
        MyItem *item = &self->items[keynum];

        return PyMyItem_New(item);
    }

    PyErr_Format(PyExc_IndexError,
                 "PyMySeq[index]: index %d out of range", keynum);
    return NULL;
}

每次我想获取序列的一个项时,都会调用PyMyItem_New函数。这在大多数情况下是好的。但对于像使用for循环这样的情况,这是非常低效的:

for i in myPyObjSeq:
    print(i)

如果我的序列有一百万个项目。这些物品将在这个循环中被创建和销毁100万次!!!你知道吗

问题是:有没有办法避免这种情况???你知道吗


Tags: 函数selfnewindexlenreturnifsq
1条回答
网友
1楼 · 发布于 2024-05-15 23:54:28

您有几个选择:

  • 首先,在cpythonapi中,分配和释放许多小对象是常见的。CPython有一个为此而优化的分配器,所以它通常是不可避免的。
    See this question for details.
  • 如果您需要循环处理数百万个项目,您可能需要考虑实现一个迭代器,这样您就可以循环处理项目,但决不能一次分配所有项目。你知道吗
  • 另一种选择,(不是那么Pythonic)-是在序列上有一个方法,它接受一个可调用的。与向list.sort(key=function)传递回调的方式类似。
    在这种情况下,您可以向每个函数传递相同的对象,使用修改后的索引
    ,但不要上当,也可以调用函数create的PyObject!你知道吗
  • 如果数据是原始的C结构,可以使用缓冲区接口公开,也可以参见内存视图。你知道吗
  • 您可以总是有一个修改到位的Python对象,但是这会给API的用户带来一些混乱,因为他们可能会访问一个索引,而没有意识到进一步的访问会改变另一个变量(不好的做法,不要这样做`)

相关问题 更多 >