【问题标题】:What does "import" prefer - .pyd (.so) or .py?“导入”更喜欢什么 - .pyd (.so) 或 .py?
【发布时间】:2020-02-29 08:34:53
【问题描述】:

我在同一个目录下有两个文件,一个编译好的库文件和一个源文件:

.
├── a.py
└── a.pyd

看起来 import a 实际上导入了 a.pyd 模块。但是我找不到一些官方文件来保证这一点。

有人知道不同文件类型的导入顺序吗?

同样的问题也适用于 Unix Python 扩展 (.so)

【问题讨论】:

  • 如果你有两个文件 a.py a.pyd 不管你想导入哪一个,都写成'import a'而不是import a.pyd
  • 在同一目录中?
  • 是在同一目录中
  • hhaha 这太有问题了,我建议您将该文件放到 2 个不同的目录中并使用路径导入它:)))
  • 但是如果你将pyd文件构建到相同的位置,如果代码错误你可以删除.pyd文件并重写py文件是非常方便的。而且程序也可以运行

标签: python python-3.x windows python-import


【解决方案1】:

在典型的 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 源代码中的优先级,请查看 here in 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 将忽略 spam.py 文件,而是加载包 spam。如果您希望模块 spam.py 具有优先权,则必须将其放在 sys.path 中较早的目录中。

(提示:搜索顺序由函数imp.get_suffixes()返回的后缀列表决定。通常按照以下顺序搜索后缀:".so", "module.so", “.py”、“.pyc”。目录没有显式出现在此列表中,但位于其中的所有条目之前。)

该文档没有明确提及“.pyd”,但这是“.so”的 Windows 等效项。我刚刚在Windows机器上测试过,确实'.pyd'出现在后缀列表中'.py'之前。

请注意,上面给出的参考资料已经很老了!自从写这篇文章以来,导入系统已经彻底改造,底层机制已经暴露给用户访问:例如,你可以改变sys.meta_path 来注册你自己的加载器或更改优先级。因此,现在可以自定义 '.py' 优先于 '.pyd',imp.get_suffixes() 对任何事情的看法并不重要(实际上,该功能现在已被弃用)。当然,默认的 Python 安装不会这样做,并且默认优先级与上面提到的参考保持相同。

【讨论】:

  • 所以不管我的情况如何。我可以使用“imp.get_suffixes()”来检查文件的顺序,对吧?
  • 就像我说的那样,该功能现在已被弃用,sys.meta_path 中的内容与此处相关。最可靠的方法是使用importlib.util.find_spec('a').loader 并查看它是解析为ExtensionFileLoader (.pyd/.so) 还是SourceFileLoader (.py)。
【解决方案2】:

感谢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 的顺序。

至少我可以区分我导入到模块化的哪个。

【讨论】:

    猜你喜欢
    • 2019-09-28
    • 2011-08-28
    • 1970-01-01
    • 2011-03-07
    • 2015-12-25
    • 2011-06-25
    • 1970-01-01
    • 1970-01-01
    • 2010-09-11
    相关资源
    最近更新 更多