Python共享对象模块命名规范

23 投票
2 回答
5511 浏览
提问于 2025-04-16 19:23

我写了一个用C++做的Python模块,并把它做成了一个共享库,运行得很好。不过在这个过程中,我通过一个叫strace的工具发现,Python在调用import时,会寻找几种不同的文件名。具体来说,当我输入import foo时,Python会按以下顺序查找:

  • foo(一个文件夹)
  • foo.so
  • foomodule.so
  • foo.py
  • foo.pyc

这些都挺好理解的,除了foomodule.so这个名字。为什么Python会同时查找名字以.so和module.so结尾的文件呢?这是历史遗留问题吗?我查了很多资料,但没有找到任何解释,现在我在想,我是不是应该把我的模块命名为foomodule.so,而不是foo.so。我的系统里似乎有一些Python模块是用这两种命名方式的,所以我不禁想知道,这些不同的名字是否有什么特别的含义。

2 个回答

10

这只是我的猜测,但我认为这和下面的内容有关,来自于用C或C++扩展Python

首先,创建一个名为spammodule.c的文件。(历史上,如果一个模块叫做spam,那么包含其实现的C文件就叫spammodule.c;如果模块名很长,比如spammify,那么这个模块的文件名可以简化为spammify.c。)

我想这个命名规则也适用于.so文件的名称。这个猜测在同一文档的1.5节中得到了进一步的支持。


根据Wladimir的出色发现,我找到了module.so作为后缀的首次引用。这是一个补丁,用于支持SunOS库的动态加载,来自“Bill”。(是Bill Jansson吗?)显然,module作为后缀的命名规则在使用.so共享库之前就已经开始了,当.so库被采用时,这个规则就被继续沿用了。

不过我觉得Wladimir是对的——有趣的变化是采用了短模块名的规则。这也证实了我之前的猜测,即长模块名是早期的命名规则。

21

其实这跟平台有关,Python会根据不同的操作系统尝试不同的后缀。下面是import.c文件中后缀表的初始化部分:

#ifdef HAVE_DYNAMIC_LOADING
    memcpy(filetab, _PyImport_DynLoadFiletab,
           countD * sizeof(struct filedescr));
#endif
    memcpy(filetab + countD, _PyImport_StandardFiletab,
           countS * sizeof(struct filedescr));
    filetab[countD + countS].suffix = NULL;

    _PyImport_Filetab = filetab;

这里面有两个列表,分别是_PyImport_DynLoadFiletab_PyImport_StandardFiletab。后者比较简单,它在同一个文件中定义为[".py", ".pyw", ".pyc"](第二个后缀只有在Windows上才有)。_PyImport_DynLoadFiletab则是在不同的dynload_<platform>.c文件中定义的。在基于Unix的系统中,它的值是[".so", "module.so"];在CygWin上,它定义为[".dll", "module.dll"];而在OS/2上是[".pyd", ".dll"],在Windows上则简单地是[".pyd"]

我查了一下源代码的历史,发现1999年有个改动,似乎是添加了"module.so"作为一个可能的后缀:http://hg.python.org/cpython-fullhistory/diff/8efa37a770c6/Python/importdl.c。这个改动最初是为了NeXTStep(后来变成了Mac OS X)做的,主要是针对特定的链接设置。我对这个操作系统不太了解,所以不太清楚为什么要这样做——我猜是为了避免命名冲突。例如,一个框架库foo.so可能已经被加载,而操作系统不允许加载同名的另一个库。所以foomodule.so是一个折衷方案,允许名为foo的Python模块存在。

编辑:上面的段落是错的——我没有追溯到足够早的历史,感谢senderle的指正。实际上,比较有趣的改动是出现在1994年的这个链接:http://hg.python.org/cpython-fullhistory/diff/2230/Python/import.c,在这里添加了一种新的模块命名方案(foo.so),作为旧方案(foomodule.so)的替代。我猜旧的命名方式在某个时候被弃用了,因为在多次重写代码时,某些平台(如Windows)已经移除了对它的支持。值得注意的是,即使在最初引入时,短模块名的版本也是排在前面的——这意味着它已经是首选的变体。

编辑2:我查了一下1994年的邮件列表/新闻组,看看这个改动是否有讨论过——看起来并没有,Guido van Rossum似乎是在没有告知任何人的情况下实现了这个改动。

撰写回答