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;
}
不,不能通过
PyListObject
上的C-API直接使用list.pop
方法假设
list.pop
已经存在并且是用C实现的,那么您可以简单地查找CPython实现的功能:Source for CPython 3.7.2
这包括许多C扩展不容易访问的函数,它还处理从特定索引(甚至是负索引)中弹出的函数。就我个人而言,我甚至不想重新实现它,只需使用^{} 调用
^{pr2}$pop
方法:它可能比重新实现慢一点,但应该“更安全”——不能意外地弄乱列表对象的不变量(例如调整大小条件)。在
另一个实现存在于Cython
^{3}$也可以根据您的用例进行调整。在
你得自己动手。以下是一个可能的实现(不进行错误检查):
^{} 只是一个访问
lst->ob_size
的宏,我们在执行pop
时减少它。在此外,还使用没有错误检查的版本,即
PyList_GET_ITEM
和PyList_GET_SIZE
,因为一旦它被建立(参见TODO注释),列表就不是空的-不会有任何问题。在调用者接收到一个新的引用,尽管
PyList_GET_ITEM
返回一个借用的引用:按照我们在上面代码中所做的那样减小列表的大小,使list“忘记”引用而不减少引用计数器。在正如@MSeifert所指出的,这个版本不会改变底层数组的大小,就像
list.pop()
所做的那样(如果在pop之后只使用了底层数组的一半或更少)。这可以看作是上述实现的“特性”——用内存交换速度。在相关问题 更多 >
编程相关推荐