名称`posix`在何处/如何通过import语句解析?
What happens behind the scenes (in CPython 3.6.0) when code uses import posix
? This module doesn't have a __file__
attribute. When starting the interpreter in verbose mode, I see this line:
当代码使用import posix时,幕后(在CPython 3.6.0中)会发生什么?该模块没有__file__属性。在详细模式下启动解释器时,我看到这一行:
import 'posix' # <class '_frozen_importlib.BuiltinImporter'>
It's already present in sys.modules
in a newly openened interpreter, and importing it just binds a name to the existing module.
它已经存在于新开放的解释器的sys.modules中,并且导入它只是将名称绑定到现有模块。
I'm trying to look at implementation detail of os.lstat
on my platform to determine if and when it uses os.stat
.
我正在尝试在我的平台上查看os.lstat的实现细节,以确定它是否以及何时使用os.stat。
1 个解决方案
#1
3
Here, have more detail than you're likely to need.
在这里,有更多的细节,而不是你可能需要的。
posix
is a built-in module. When you hear "built-in module", you might think of ordinary standard library modules, or you might think of modules written in C, but posix
is more built-in than most.
posix是一个内置模块。当您听到“内置模块”时,您可能会想到普通的标准库模块,或者您可能会想到用C语言编写的模块,但是posix比大多数都更加内置。
The posix
module is written in C, in Modules/posixmodule.c
. However, while most C modules, even standard library C modules, are compiled to .so
or .pyd
files and placed on the import path like regular Python modules, posix
actually gets compiled right into the Python executable itself.
posix模块用C语言编写,在Modules / posixmodule.c中。然而,虽然大多数C模块,甚至是标准库C模块,都被编译为.so或.pyd文件,并像常规Python模块一样放在导入路径上,但实际上posix被编译到Python可执行文件中。
One of the internal details of CPython's import system is the PyImport_Inittab
array:
CPython导入系统的一个内部细节是PyImport_Inittab数组:
extern struct _inittab _PyImport_Inittab[];
struct _inittab *PyImport_Inittab = _PyImport_Inittab;
This is an array of struct _inittab
s, which consist of a name and a C module initialization function for the module with that name. Modules listed here are built-in.
这是一个struct _inittabs数组,它由具有该名称的模块的名称和C模块初始化函数组成。此处列出的模块是内置的。
This array is initially set to _PyImport_Inittab
, which comes from Modules/config.c
(or PC/config.c
depending on your OS, but that's not the case here). Unfortunately, Modules/config.c
is generated from Modules/config.c.in
during the Python build process, so I can't show you a source code link, but here's part of what it looks like when I generate the file:
此数组最初设置为_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},
// ...
As you can see, there's an entry for the posix
module, along with the module initialization function, PyInit_posix
.
如您所见,posix模块有一个条目,还有模块初始化函数PyInit_posix。
As part of the import system, when trying to load a module, Python goes through sys.meta_path
, a list of module finders. One of these finders is responsible for performing the sys.path
search you're likely more familiar with, but one of the others is _frozen_importlib.BuiltinImporter
, responsible for finding built-in modules like posix
. When Python tries that finder, it runs the finder's find_spec
method:
作为导入系统的一部分,当尝试加载模块时,Python会通过sys.meta_path,这是一个模块查找器列表。其中一个查找程序负责执行您可能更熟悉的sys.path搜索,但其中一个是_frozen_importlib.BuiltinImporter,负责查找像posix这样的内置模块。当Python尝试该查找器时,它运行finder的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
which uses _imp.is_builtin
to search PyImport_Inittab
for the "posix"
name. The search finds the name, so find_spec
returns a module spec representing the fact that the loader for built-in modules should handle creating this module. (The loader is the second argument to spec_from_loader
. It's cls
here, because BuiltinImporter
is both the finder and loader.)
它使用_imp.is_builtin在PyImport_Inittab中搜索“posix”名称。搜索找到名称,因此find_spec返回一个模块规范,表示内置模块的加载器应该处理创建此模块的事实。 (加载器是spec_from_loader的第二个参数。这是cls,因为BuiltinImporter既是finder又是loader。)
Python then runs the loader's create_module
method to generate the module object:
然后Python运行加载器的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)
which delegates to _imp.create_builtin
, which searches PyImport_Inittab
for the module name and runs the corresponding initialization function.
委托给_imp.create_builtin,它在PyImport_Inittab中搜索模块名称并运行相应的初始化函数。
(_call_with_frames_removed(x, y)
just calls x(y)
, but part of the import system treats it as a magic indicator to strip importlib
frames from stack traces, which is why you never see those frames in the stack trace when your imports go wrong.)
(_call_with_frames_removed(x,y)只调用x(y),但导入系统的一部分将其视为从堆栈跟踪中剥离importlib帧的魔术指示器,这就是为什么当你的导入时你从未在堆栈跟踪中看到这些帧的原因错误。)
If you want to see more of the code path involved, you can look through Lib/importlib/_bootstrap.py
, where most of the import implementation lives, Python/import.c
, where most of the C part of the implementation lives, and Python/ceval.c
, which is where the bytecode interpreter loop lives, and thus is where execution of an import
statement starts, before it reaches the more core parts of the import machinery.
如果你想看到更多涉及的代码路径,你可以查看Lib / importlib / _bootstrap.py,其中大多数导入实现存在,Python / import.c,其中大多数C部分的实现存在,以及Python / ceval.c,它是字节码解释器循环所在的位置,因此是导入语句执行到达导入机制的更核心部分之前的地方。
Relevant documentation includes the section of the language reference on the import system, as well as PEPs 451 and 302. There isn't much documentation on built-in modules, although I did find a bit of documentation targeted toward people embedding Python in other programs, since they might want to modify PyImport_Inittab
, and there is the sys.builtin_module_names
list.
相关文档包括导入系统的语言参考部分,以及PEP 451和302.关于内置模块的文档并不多,尽管我确实找到了一些针对在其他程序中嵌入Python的人的文档,因为他们可能想要修改PyImport_Inittab,并且有sys.builtin_module_names列表。
更多相关文章
- Python常用模块-摘要算法(hashlib)
- Python学习系列(六)(模块)
- Python NameError:全局名称“Form”没有定义pyqt
- Python(名称空间、函数嵌套、函数对象)
- python,os模块的常用方法
- python3中time模块的用法及说明
- Python学习笔记(基础篇)_014_GUI模块 easygui的使用
- 如何使用pip安装Python MySQLdb模块?
- 在模块和/或包中组织Python类