- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
模块加载如何在CPython的幕后工作?特别是,用C编写的扩展的动态加载如何工作?我在哪里可以了解到?
我发现源代码本身不堪重负。我可以看到,在支持它的系统上使用了可信赖的ol'dlopen()
和友人,但是对总体情况没有任何了解,这将需要很长时间才能从源代码中弄清楚。
关于这个话题可以写很多,但据我所知,几乎没有任何东西-大量描述Python语言本身的网页使搜索变得很困难。一个很好的答案将提供一个合理的简要概述,并提供我可以学到更多资源的参考。
我最关心的是在类似Unix的系统上这是如何工作的,仅因为这就是我所知道的,但是我对过程在其他地方是否类似感兴趣。
更具体地说(可能冒太多的风险),CPython如何使用模块方法表和初始化函数来“理解”动态加载的C?
最佳答案
TLDR短版本以粗体显示。
对Python源代码的引用基于版本2.7.6。
Python通过动态加载导入大多数用C编写的扩展。动态加载是一个深奥的主题,虽然没有充分的文档记载,但这是绝对的前提。在解释Python如何使用它之前,我必须简要解释一下它是什么以及Python为什么使用它。
历史上,Python的C扩展静态地与Python解释器本身联系在一起。这要求Python用户每次想使用用C编写的新模块时都要重新编译解释器。正如您可以想象的那样,作为Guido van Rossum describes,随着社区的发展,这变得不切实际。如今,大多数Python用户从未编译过解释器。我们只是简单地“ pip安装模块”,然后“导入模块”,即使该模块包含已编译的C代码。
链接使我们能够跨编译的代码单元进行函数调用。当在运行时决定要链接的内容时,动态加载解决了链接代码的问题。也就是说,它允许正在运行的程序与链接器交互,并告诉链接器它要链接的内容。为了让Python解释器使用C代码导入模块,这就是需要的。编写在运行时做出此决定的代码非常少见,并且大多数程序员会对它的实现感到惊讶。简而言之,C函数有一个地址,它希望您将某些数据放在某些位置,并保证在返回时将某些数据放在某些位置。如果您知道秘密握手,则可以调用它。
动态加载的挑战在于,程序员必须正确地进行握手,并且没有安全检查。至少,没有为我们提供它们。通常,如果我们尝试使用错误的签名来调用函数名称,则会出现编译或链接器错误。对于动态加载,我们在运行时按名称(“符号”)要求链接器提供功能。链接器可以告诉我们是否找到了该名称,但无法告诉我们如何调用该函数。它只是给我们一个地址-空指针。我们可以尝试将其强制转换为某种函数指针,但这完全取决于程序员是否正确进行了强制转换。如果我们在转换中错误地获得了函数签名,那么对于编译器或链接器来说,警告我们为时已晚。该程序失控并最终导致对内存的不当访问后,我们可能会遇到段错误。使用动态加载的程序必须依赖于预先安排的约定和在运行时收集的信息来进行正确的函数调用。这是处理Python解释器之前的一个小示例。
文件1:main.c
/* gcc-4.8 -o main main -ldl */
#include <dlfcn.h> /* key include, also in Python/dynload_shlib.c */
/* used for cast to pointer to function that takes no args and returns nothing */
typedef void (say_hi_type)(void);
int main(void) {
/* get a handle to the shared library dyload1.so */
void* handle1 = dlopen("./dyload1.so", RTLD_LAZY);
/* acquire function ptr through string with name, cast to function ptr */
say_hi_type* say_hi1_ptr = (say_hi_type*)dlsym(handle1, "say_hi1");
/* dereference pointer and call function */
(*say_hi1_ptr)();
return 0;
}
/* error checking normally follows both dlopen() and dlsym() */
/* gcc-4.8 -o dyload1.so dyload1.c -shared -fpic */
/* compile as C, C++ does name mangling -- changes function names */
#include <stdio.h>
void say_hi1() {
puts("dy1: hi");
}
/* ./configure sets HAVE_DYNAMIC_LOADING if dynamic loading of modules is
supported on this platform. configure will then compile and link in one
of the dynload_*.c files, as appropriate. We will call a function in
those modules to get a function pointer to the module's init function.
*/
Python/dynload_aix.c Python/dynload_beos.c Python/dynload_hpux.c
Python/dynload_os2.c Python/dynload_stub.c Python/dynload_atheos.c
Python/dynload_dl.c Python/dynload_next.c Python/dynload_shlib.c
Python/dynload_win.c
dl_funcptr _PyImport_GetDynLoadFunc(const char *fqname, const char *shortname,
const char *pathname, FILE *fp)
handle = dlopen(pathname, dlopenflags);
/* error handling */
p = (dl_funcptr) dlsym(handle, funcname);
return p;
PyOS_snprintf(funcname, sizeof(funcname),
LEAD_UNDERSCORE "init%.200s", shortname);
PyMODINIT_FUNC
initspam(void)
{
PyObject *m;
m = Py_InitModule("spam", SpamMethods);
if (m == NULL)
return;
}
>>> import spam
ImportError: No module named spam
>>> import notspam
ImportError: dynamic module does not define init function (initnotspam)
SystemError: dynamic module not initialized properly
static PyMethodDef SpamMethods[] = {
{"system", spam_system, METH_VARARGS,
"Execute a shell command."},
{NULL, NULL, 0, NULL}
};
struct PyMethodDef {
const char *ml_name; /* The name of the built-in function/method */
PyCFunction ml_meth; /* The C function that implements it */
int ml_flags; /* Combination of METH_xxx flags, which mostly
describe the args expected by the C func */
const char *ml_doc; /* The __doc__ attribute, or NULL */
};
typedef PyObject *(*PyCFunction)(PyObject *, PyObject *);
if (flags & (METH_NOARGS | METH_O)) {
PyCFunction meth = PyCFunction_GET_FUNCTION(func);
PyObject *self = PyCFunction_GET_SELF(func);
if (flags & METH_NOARGS && na == 0) {
C_TRACE(x, (*meth)(self,NULL));
}
meth
分配了一个函数指针,然后将其取消引用并调用。返回值以x结尾。
关于python - 模块加载在CPython中如何工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25678174/
如果您使用 -i 选项调用 cpython 解释器,它会在完成任何命令或脚本后进入交互模式。有没有办法在程序中让解释器执行此操作,即使它没有给出 -i?明显的用例是在异常情况发生时通过交互式检查状态进
我是按照官方cpython代码link here上的说明操作的.我做了一个 hg update 3.5 然后做了以下。 sudo apt-get build-dep python3.5 但它抛出了一个
我打算尝试使用 PyPy。但是我用 rust-cpython 编写的扩展(.so 文件)在使用 pypy3 执行时无法加载: ImportError: No module named 'pkg.lib
我试图配置预提交挂接,在运行预提交运行--所有文件时,我收到以下错误:。我已尝试升级pip以解决此问题pip安装--升级pip,但我收到另一个错误:。我尝试检查PIP和PIP3的版本,但现在我也收到了
我想为 android 创建电影下载应用程序以供学习。 为了方便开发,我想使用 youtube-dl 作为下载器后端。 所以我想将 Cpython 运行时和 ffmpeg(用于转换电影格式)嵌入到 A
我有一个 Windows fatal exception: code 0xc0000374 - 是的,有多处理(等待但是......)。 Google 表示异常代码 0xc0000374 表示堆损坏。
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我刚刚成功编译了 C++ 类的 Python 包装器。但是,当我尝试将模块加载到 Python 时(通过 import cell),我收到以下消息: ImportError: dynamic modu
在我用 python 函数包装的一个 C++ 源文件中,有人包含了以下内容: namespace some_namespace { static double some_double; } flo
例如,0 STORE_NAME 0 (sys) 是import sys 指令的一部分。这种指令格式有任何文档吗?更何况,这种格式是Python的标准吗?还是具体实现? 最佳答案 即Python byt
我有这个故意不高效的代码: def suffix_array_alternative_naive(s): return [rank for suffix, rank in sorted((s[
应该如何编写 CPython 扩展,以便 pydoc 提及参数名称而不是 (...)? 我关注了 official python tutorial about extending Python ,甚至
我正在尝试在运行 Raspbian Jessie 的 Raspberry Pi 上从源代码构建和安装 python 3.6.2。以下是构建过程的过程: $ ./configure --enable-o
GAE 有各种限制,其中之一是最大的可分配内存块大小为 1Mb(现在是 10 倍,但这并没有改变问题)。这一限制意味着不能在 list() 中放置超过一定数量的项目,因为 CPython 会尝试为元素
我和一个 friend 聊天,比较语言,他提到 Java 的自动内存管理优于 Python,因为 Java 有压缩,而 Python 没有——因此对于长时间运行的服务器,Python 是一个糟糕的选择
我一直在深入研究源代码,以找出打印结果的时间点。例如: >>> x = 1 >>> x + 2 3 以上两条语句编译为: 1 0 LOAD_CONST
我最近在生产系统中发现了一个潜在的错误,其中两个字符串使用身份运算符进行比较,例如: if val[2] is not 's': 我想这无论如何都会经常起作用,因为据我所知,CPython 将短的不可
Python 允许字符串乘以整数: >>> 'hello' * 5 'hellohellohellohellohello' 这是如何在 CPython 中实现的? 我特别感谢指向源代码的指针; the
我正在阅读 this page在文档中,并注意到它说 This is the full Python grammar, as it is read by the parser generator an
我目前正在制作 CPython 3.0 Python 解释器的嵌入式系统端口,我对任何引用资料或文档特别感兴趣,这些引用资料或文档提供有关版本 3.0 的代码设计和结构的详细信息,甚至是任何2.x 版
我是一名优秀的程序员,十分优秀!