Abd*_*P M 4 python cpython list python-c-api python-3.x
让我说我有一个PyListObject,我想附加一个PyObject然后我可以使用PyList_Append记录在其中的API List Objects C-API.但是对于我的用例,我想要pop一个元素PyListObject(即my_list.pop()在python层中).
但是List Objects C-API文档没有提到有关pop操作的任何内容.
那么有关于PyListPopAPI函数的文档吗?
不,该list.pop方法不能通过C-API直接获得PyListObject.
鉴于list.pop已经存在并且在C中实现,您可以简单地查找CPython实现的功能:
static PyObject *
list_pop_impl(PyListObject *self, Py_ssize_t index)
{
PyObject *v;
int status;
if (Py_SIZE(self) == 0) {
/* Special-case most common failure cause */
PyErr_SetString(PyExc_IndexError, "pop from empty list");
return NULL;
}
if (index < 0)
index += Py_SIZE(self);
if (index < 0 || index >= Py_SIZE(self)) {
PyErr_SetString(PyExc_IndexError, "pop index out of range");
return NULL;
}
v = self->ob_item[index];
if (index == Py_SIZE(self) - 1) {
status = list_resize(self, Py_SIZE(self) - 1);
if (status >= 0)
return v; /* and v now owns the reference the list had */
else
return NULL;
}
Py_INCREF(v);
status = list_ass_slice(self, index, index+1, (PyObject *)NULL);
if (status < 0) {
Py_DECREF(v);
return NULL;
}
return v;
}
Run Code Online (Sandbox Code Playgroud)
这包括很多不能(容易)访问C扩展的函数,它还处理来自特定索引(甚至是负索引)的弹出.就个人而言,我甚至懒得重新实现它,但只需调用pop方法PyObject_CallMethod:
PyObject *
list_pop(PyObject *lst){
return PyObject_CallMethod(lst, "pop", "n", Py_SIZE(lst) - 1);
}
Run Code Online (Sandbox Code Playgroud)
它可能比重新实现慢一点但它应该"更安全" - 不能意外地弄乱列表对象的不变量(例如调整大小条件).
Cython中提供了另一种实现方式
static CYTHON_INLINE PyObject* __Pyx_PyList_Pop(PyObject* L) {
/* Check that both the size is positive and no reallocation shrinking needs to be done. */
if (likely(PyList_GET_SIZE(L) > (((PyListObject*)L)->allocated >> 1))) {
Py_SIZE(L) -= 1;
return PyList_GET_ITEM(L, PyList_GET_SIZE(L));
}
return CALL_UNBOUND_METHOD(PyList_Type, "pop", L);
}
Run Code Online (Sandbox Code Playgroud)
这也适用于您的用例.
| 归档时间: |
|
| 查看次数: |
201 次 |
| 最近记录: |