【问题标题】:What is the mechanism in CPython for invoking a Python function from C code?CPython 中从 C 代码调用 Python 函数的机制是什么?
【发布时间】:2020-03-15 22:42:53
【问题描述】:

假设我正在编写一个 CPython C 扩展,并且我想在其中调用一些用 Python 编写的函数。

互联网表明它涉及从 C 扩展名调用 PyObject *PyObject_Call()。是这样吗?

如果是,我想了解 VM 内部调用被调用 Python 函数的机制。我花时间浏览了PyObject *PyObject_Call() 的源代码,但无法完全掌握其中的内容,敬请指教。

下列哪一项是正确的?

  1. VM 推送一个新的堆栈帧等 - 但随后等待下一个 eval 循环迭代自然地将控制权切换到调用的 Python 函数

  2. VM 调用一个新的字节码解释循环以便立即解释被调用的函数

  3. 还有别的吗?

【问题讨论】:

    标签: python virtual-machine cpython


    【解决方案1】:

    它是 2。这也是用于从 Python 代码中调用 Python 函数的相同机制。字节码评估循环的一个实例用于每个 Python 堆栈帧,并且评估循环是可重入的。

    PyObject_Call 是一个合适的函数。 (还有其他的,有时可能更方便,但PyObject_Call 是通用的。)您可能无法理解它的作用,因为它只是一个调度程序。它委托给被调用对象的函数调用运算符的实现。

    对于普通的 Python 函数对象,您可以在 Objects/funcobject.c 中找到 function_call,您可以通过 _PyFunction_FastCallDict 跟踪调用,最终到 PyEval_EvalFrameEx。这会调用interp->eval_frame,其中defaults_PyEval_EvalFrameDefault,其中包含字节码评估循环。

    【讨论】:

    • 我非常感谢详细的答案,尤其是实际源代码的链接。很有帮助,谢谢!只是为了确认我的理解的问题:这是否意味着在运行的 CPython 进程中,对于每个 Python 级堆栈帧,总是有一个对应的原生 C 级堆栈帧?
    • @AvivCohn:是的。 (也有大量的 C 栈帧与 Python 栈帧不对应。)
    • 非常有趣,我从来不知道。我想知道它在其他语言实现中是如何完成的,会去做一些研究。无论如何,非常感谢! :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-22
    • 1970-01-01
    • 1970-01-01
    • 2013-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多