C实现python的len函数的解释

Sim*_*011 -7 c python cpython python-internals

当我遇到len函数的C实现时,我正在阅读有关python内置函数的实现的信息。

static PyObject *
builtin_len(PyObject *module, PyObject *obj)
/*[clinic end generated code: output=fa7a270d314dfb6c input=bc55598da9e9c9b5]*/
{
Py_ssize_t res;

res = PyObject_Size(obj);
if (res < 0) {
    assert(PyErr_Occurred());
    return NULL;
}
return PyLong_FromSsize_t(res);
Run Code Online (Sandbox Code Playgroud)

我无法理解这段代码中发生了什么。我不知道C是如何工作的。有人可以解释这段代码在做什么吗?

我从https://github.com/python/cpython/blob/master/Python/bltinmodule.c获取了代码

编辑:我只是很好奇len函数是如此之快,在这段代码中绊倒了。我只想知道为什么使用函数PyObject_Size检查对象的大小为零,然后使用PyLong_FromSsize_t返回实际大小。

Ant*_*ala 5

功能没有什么特别的。通常,用C编写的函数(尤其是那些不调用Python代码的函数)比用Python编写的函数要快得多。

我在这里特地采取一种立场,即读者知道 C的工作方式,否则解释将是一本书。

builtin_len是当被称为一个len(foo)在Python代码被执行。PyObject *obj函数的自变量引用作为自变量(foo)给出的对象,PyObject *self并将包含对的包含模块的引用builtin_len

Python中的每个容器的长度必须在0到所允许的最大值之间Py_ssize_tPyObject_Size(obj);是一个函数/宏,它通过obj->ob_type->tp_as_sequence->sq_length或获得给定对象的大小obj->ob_type->tp_as_mapping->mp_length。如果发生错误,则会为当前线程设置一个引发异常的异常,并返回一个数字<0(-1)。

return NULL;表示呼叫者已发生异常,就必须采取相应的行动-如果它是在Python字节码的函数调用指令时,会导致异常升高; 如果是C代码,则它将以类似于此函数的方式工作-如果发生异常,则返回NULL或无效值;或者它可以清除异常或将其替换为另一个。

否则,如果大于或等于0,则返回一个现有对象或构造一个新对象,Py_ssize_t res将C整数类型的C整数类型转换为Python int对象int。由于历史原因,在CPython 3中int调用PyLong了Python 对象。PyLong_FromSsize_t()是众多函数之一-该函数能够将任何类型的值转换Py_ssize_tint具有相同值的Python 。像所有其他对象一样,对此对象的引用将保留为指向(半透明)PyObject结构的指针,并将其返回。

assert(PyErr_Occurred());是一个仅在Python的调试版本中有效的断言。它断言,如果从处获得负数PyObject_Size,表示抛出了异常,则该异常也已正确设置;如果不存在,它将直接终止整个CPython进程。它在Python的发行版本中无效,因为“声明永不失败”。