C 实现 python 的 len 函数的解释
explanation of C implementation python's len function
当我遇到 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);
我无法理解这段代码中发生的事情。我不知道 C 是如何工作的。有人可以解释这段代码的作用吗?
我从 https://github.com/python/cpython/blob/master/Python/bltinmodule.c
获得了代码
编辑:我只是好奇 len 函数为何如此之快,无意中发现了这段代码。我只想知道为什么函数 PyObject_Size 用于检查对象的大小为零,然后 PyLong_FromSsize_t 到 return 实际大小。
这个函数没有什么特别的。通常用C写的函数,尤其是那些不调用Python代码的函数,比用Python.
写的要快很多
我这里的立场是reader 知道 C 是怎么工作的,否则解释宁愿是一本书。
builtin_len
是在Python代码中执行len(foo)
时调用的那个。函数的 PyObject *obj
参数引用作为参数给出的对象 (foo
),并且 PyObject *self
将包含对 builtin_len
.[=32= 的包含模块的引用]
Python 中的每个容器的长度必须介于 0 和 Py_ssize_t
允许的最大值之间。 PyObject_Size(obj);
是一个 function/macro,通过其 obj->ob_type->tp_as_sequence->sq_length
或 obj->ob_type->tp_as_mapping->mp_length
获取给定对象的大小。出错时会为当前线程设置引发异常,并返回一个 < 0 (-1) 的数字。
return NULL;
表示调用者发生了异常,必须进行相应处理——如果是Python字节码中的函数调用指令,则会引发异常;如果它是 C 代码,那么它将以类似于此函数的方式运行 - 如果发生异常,则返回 NULL 或无效值;或者它可以清除异常或用另一个替换它。
否则如果大于等于0,则C整数类型的Py_ssize_t res
转换为Pythonint
对象,通过返回现有的 int
对象或构造一个新对象。由于历史原因,Python int
对象在 CPython 3 中被称为 PyLong
。 PyLong_FromSsize_t()
是众多函数之一 - 这个函数能够将 Py_ssize_t
类型的任何值转换为具有相同值的 Python int
。与所有其他对象一样,对该对象的引用被保存为指向(半不透明)PyObject
结构的指针,并返回 this。
assert(PyErr_Occurred());
是仅在 Python 的调试版本中有效的断言。它断言从 PyObject_Size
得到负数后,表示抛出异常,异常也已正确设置;如果不存在,它将完全中止整个 CPython 进程。它在 Python 的发布版本中无效,因为 "asserts never fail".
当我遇到 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);
我无法理解这段代码中发生的事情。我不知道 C 是如何工作的。有人可以解释这段代码的作用吗?
我从 https://github.com/python/cpython/blob/master/Python/bltinmodule.c
获得了代码编辑:我只是好奇 len 函数为何如此之快,无意中发现了这段代码。我只想知道为什么函数 PyObject_Size 用于检查对象的大小为零,然后 PyLong_FromSsize_t 到 return 实际大小。
这个函数没有什么特别的。通常用C写的函数,尤其是那些不调用Python代码的函数,比用Python.
写的要快很多我这里的立场是reader 知道 C 是怎么工作的,否则解释宁愿是一本书。
builtin_len
是在Python代码中执行len(foo)
时调用的那个。函数的 PyObject *obj
参数引用作为参数给出的对象 (foo
),并且 PyObject *self
将包含对 builtin_len
.[=32= 的包含模块的引用]
Python 中的每个容器的长度必须介于 0 和 Py_ssize_t
允许的最大值之间。 PyObject_Size(obj);
是一个 function/macro,通过其 obj->ob_type->tp_as_sequence->sq_length
或 obj->ob_type->tp_as_mapping->mp_length
获取给定对象的大小。出错时会为当前线程设置引发异常,并返回一个 < 0 (-1) 的数字。
return NULL;
表示调用者发生了异常,必须进行相应处理——如果是Python字节码中的函数调用指令,则会引发异常;如果它是 C 代码,那么它将以类似于此函数的方式运行 - 如果发生异常,则返回 NULL 或无效值;或者它可以清除异常或用另一个替换它。
否则如果大于等于0,则C整数类型的Py_ssize_t res
转换为Pythonint
对象,通过返回现有的 int
对象或构造一个新对象。由于历史原因,Python int
对象在 CPython 3 中被称为 PyLong
。 PyLong_FromSsize_t()
是众多函数之一 - 这个函数能够将 Py_ssize_t
类型的任何值转换为具有相同值的 Python int
。与所有其他对象一样,对该对象的引用被保存为指向(半不透明)PyObject
结构的指针,并返回 this。
assert(PyErr_Occurred());
是仅在 Python 的调试版本中有效的断言。它断言从 PyObject_Size
得到负数后,表示抛出异常,异常也已正确设置;如果不存在,它将完全中止整个 CPython 进程。它在 Python 的发布版本中无效,因为 "asserts never fail".