当代码使用import posix
时幕后(在CPython 3.6.0中)会发生什么?此模块没有__file__
属性。在详细模式下启动解释器时,我看到这一行:
import 'posix' # <class '_frozen_importlib.BuiltinImporter'>
它已经在sys.modules
中出现在一个新开放的解释器中,导入它只是将一个名称绑定到现有模块。
我正在尝试查看平台上os.lstat
的实施细节,以确定它是否以及何时使用os.stat
。
答案 0 :(得分:3)
在这里,有更多细节,而不是你可能需要的。
posix
是一个内置模块。当您听到“内置模块”时,您可能会想到普通的标准库模块,或者您可能会想到用C语言编写的模块,但posix
比大多数模块更内置。
posix
模块是用Modules/posixmodule.c
中的C语言编写的。但是,虽然大多数C模块,甚至是标准库C模块,都被编译为.so
或.pyd
文件并放置在导入路径上,就像常规Python模块一样,posix
实际上被编译到了Python可执行文件本身。
CPython导入系统的一个内部细节是PyImport_Inittab
array:
extern struct _inittab _PyImport_Inittab[];
struct _inittab *PyImport_Inittab = _PyImport_Inittab;
这是一个struct _inittab
的数组,它由具有该名称的模块的名称和C模块初始化函数组成。此处列出的模块是内置的。
此数组最初设置为_PyImport_Inittab
,来自Modules/config.c
(或PC/config.c
,具体取决于您的操作系统,但这不是这种情况)。不幸的是,Modules/config.c
是在Python构建过程中从Modules/config.c.in
生成的,因此我无法向您展示源代码链接,但这是我生成文件时的部分内容:
struct _inittab _PyImport_Inittab[] = {
{"_thread", PyInit__thread},
{"posix", PyInit_posix},
// ...
如您所见,posix
模块的条目以及模块初始化函数PyInit_posix
。
作为导入系统的一部分,在尝试加载模块时,Python会通过sys.meta_path
,即模块finders的列表。其中一个查找程序负责执行您可能更熟悉的sys.path
搜索,但其中一个是_frozen_importlib.BuiltinImporter
,负责查找posix
等内置模块。当Python尝试该查找程序时,它运行查找程序的find_spec
方法:
@classmethod
def find_spec(cls, fullname, path=None, target=None):
if path is not None:
return None
if _imp.is_builtin(fullname):
return spec_from_loader(fullname, cls, origin='built-in')
else:
return None
使用_imp.is_builtin
在PyImport_Inittab
中搜索"posix"
名称。搜索找到名称,因此find_spec
返回一个模块规范,表示内置模块的加载器应该处理创建此模块的事实。 (加载器是spec_from_loader
的第二个参数。这里是cls
,因为BuiltinImporter
既是查找器又是加载器。)
create_module
方法来生成模块对象:
@classmethod
def create_module(self, spec):
"""Create a built-in module"""
if spec.name not in sys.builtin_module_names:
raise ImportError('{!r} is not a built-in module'.format(spec.name),
name=spec.name)
return _call_with_frames_removed(_imp.create_builtin, spec)
委托给_imp.create_builtin
,part of the import system搜索PyImport_Inittab
以获取模块名称并运行相应的初始化函数。
(_call_with_frames_removed(x, y)
只调用x(y)
,但Lib/importlib/_bootstrap.py
将其视为从堆栈跟踪中剥离importlib
帧的神奇指标,这就是为什么你永远不会看到这些帧的原因导入错误时的堆栈跟踪。)
如果您想查看更多涉及的代码路径,可以查看大多数导入实现所在的Python/import.c
,Python/ceval.c
,其中大部分C部分都存在,和section of the language reference on the import system,它是字节码解释器循环所在的位置,因此是import
语句的执行开始之前,它到达导入机制的更核心部分之前。
相关文档包括451,以及PEP 302和a bit of documentation。关于内置模块的文档并不多,虽然我确实发现sys.builtin_module_names
针对的是人们将Python嵌入到其他程序中,因为他们可能想要修改PyImport_Inittab
,并且{{3}} } list。