我在同一目录中有两个文件,一个编译的库文件和源文件:
.
├── a.py
└── a.pyd
看起来像是import a
实际导入了a.pyd
模块。但我找不到任何官方文件来保证这一点。
有人知道不同文件类型的导入顺序吗?
这个问题同样适用于Unix Python扩展(.so(
在典型的Python安装中,ExtensionFileLoader
类的优先级高于用于.py
文件的SourceFileLoader
。它是处理.pyd
文件导入的ExtensionFileLoader
,在Windows机器上,你会发现.pyd
在importlib.machinery.EXTENSION_SUFFIXES
中注册(注意:在Linux/macOS上,它会在那里有.so
(。
因此,在同一目录内发生名称冲突的情况下(按顺序查看sys.path
时意味着"平局"(,a.pyd
文件优先于a.py
文件。您可以验证在创建空的a.pyd
和a.py
文件时,语句import a
是否尝试加载DLL(当然会失败(。
要查看CPython源中的优先级,请查看importlib._bootstrap_external. _get_supported_file_loaders
:中的此处
def _get_supported_file_loaders():
"""Returns a list of file-based module loaders.
Each item is a tuple (loader, suffixes).
"""
extensions = ExtensionFileLoader, _imp.extension_suffixes()
source = SourceFileLoader, SOURCE_SUFFIXES
bytecode = SourcelessFileLoader, BYTECODE_SUFFIXES
return [extensions, source, bytecode] # <-- extensions before source!
有关文档参考,请参阅http://www.python.org/doc/essays/packages/
如果我有一个同名的模块和一个包怎么办
您可能有一个目录(在sys.path上(,其中既有模块spam.py,也有包含_init_.py的子目录spam(如果没有_init_.py,目录将不会被识别为包(。在这种情况下,子目录具有优先级,导入垃圾邮件将忽略spam.py文件,而加载包垃圾邮件。如果您希望模块spam.py具有优先级,则必须将其放置在sys.path.中较早的目录中
(提示:搜索顺序由函数imp.get_suffixes((返回的后缀列表决定。通常按以下顺序搜索后缀:"。因此"模块.so"&";。py"&";。pyc">。目录没有明确地出现在这个列表中,但在其中的所有条目之前。(
此文档没有明确提到"。pyd";,但这相当于Windows中的";。所以";。我刚刚在Windows机器上进行了测试,实际上'.pyd'
出现在后缀列表中的'.py'
之前。
请注意,上面给出的参考文献非常古老!自从写了这篇文章以来,导入系统已经进行了彻底的改进,底层机制已经公开供用户访问:例如,您可以更改sys.meta_path
来注册自己的加载程序或更改优先级。因此,现在可以自定义".py"而不是".pyd",而且imp.get_suffixes()
对任何事情都有什么看法并不重要(实际上,该函数现在已被弃用(。当然,默认的Python安装不会做到这一点,默认的优先级与上面提到的参考相同。
感谢wim的回答。
import importlib.util
print(importlib.util.find_spec('a'))
显示结果
ModuleSpec(name='a', loader=<_frozen_importlib_external.ExtensionFileLoader object at 0x02A79EF0>, origin='a.pyd')
尽管我看不出pyd的顺序,py。
至少我可以区分我导入模块化的是哪一个。