【问题标题】:explanation of C implementation python's len function [closed]C实现python的len函数的解释[关闭]
【发布时间】:2019-05-28 00:38:01
【问题描述】:

当我遇到 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 返回实际大小。

【问题讨论】:

  • “我不知道 C 是如何工作的” - 那先学吧? SO 不是教程服务
  • “我不知道 C 是如何工作的” 至少要对 C 语法有一个基本的了解。没有人可以在一个 SO 答案中教你 C
  • 我只是好奇 len 函数怎么这么快并且偶然发现了这段代码。我不是要求获得 C 教程。我只是想知道为什么函数 PyObject_Size 用于检查对象的大小为零,然后 PyLong_FromSsize_t 返回实际大小
  • 你检查过这些函数是做什么的吗?你了解 Python 类型系统是如何在 CPython 中实现的吗? (提示:您不能将 Py_ssize_t 返回给 Python)
  • 我不是程序员,我只是用python来涉足数据科学、机器学习的乐趣。我的目的不是成为 Python 或 CPython 专家。我不知道我必须成为专家才能提出关于 SO 的问题。我只是好奇而已。是的,我试图找到这些功能的实现,但没能找到。

标签: python c cpython python-internals


【解决方案1】:

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

我在这里特别表明读者知道 C 是如何工作的,否则解释宁愿是一本书。

builtin_len 是在 Python 代码中执行 len(foo) 时调用的那个。函数的 PyObject *obj 参数引用作为参数给出的对象 (foo),PyObject *self 将包含对 builtin_len 的包含模块的引用。

Python 中的每个容器的长度必须介于 0 和 Py_ssize_t 允许的最大值之间。 PyObject_Size(obj); 是一个函数/宏,它通过其obj-&gt;ob_type-&gt;tp_as_sequence-&gt;sq_lengthobj-&gt;ob_type-&gt;tp_as_mapping-&gt;mp_length 获取给定对象的大小。出错时会为当前线程设置一个异常,并返回一个数字

return NULL; 表示调用者发生了异常,它必须采取相应的行动——如果是 Python 字节码中的函数调用指令,则会引发异常;如果它是 C 代码,那么它将以类似于此函数的方式运行 - 如果发生异常,则返回 NULL 或无效值;或者它可以清除异常或用另一个替换它。

否则如果大于或等于0,则C整数类型的Py_ssize_t res被转换为Python int对象,通过以下任一方式返回一个现有的int 对象或构造一个新对象。由于历史原因,Python int 对象在 CPython 3 中称为 PyLongPyLong_FromSsize_t() 是众多函数之一 - 这个函数能够将 Py_ssize_t 类型的任何值转换为具有相同值的 Python int。与所有其他对象一样,对该对象的引用作为指向(半透明)PyObject 结构的指针保存,并返回。

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

【讨论】:

  • 很好的答案,但 OP 明确地 写道 “我不知道 C 是如何工作的”
  • 非常感谢,我用谷歌搜索了很多字词就能理解你的答案。
猜你喜欢
  • 1970-01-01
  • 2011-01-12
  • 2021-05-19
  • 1970-01-01
  • 2016-10-13
  • 2019-04-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多