Python:强制导入更喜欢 .py 而不是 .so

标签 python python-3.x import cython python-import

我的情况是,同一个 Python 模块存在于两个不同版本的同一个目录中; mymodule.pymymodule.so(我通过 Cython 从第一个中获得后者,但这与我的问题无关)。当我使用 Python 时

import mymodule

它总是选择 mymodule.so。有时我真的很想导入 mymodule.py。我可以暂时将 mymodule.so 移动到另一个位置,但是如果我同时运行另一个需要导入 mymodule.so 的 Python 实例,那效果就不好了。

问题是如何使 import 更喜欢 .py 文件而不是 .so,而不是相反?

以下是我对解决方案的看法: 我想象使用 importlib 表演一些魔术并可能编辑 sys.meta_path。具体来说,我看到 sys.meta_path[2] 包含 _frozen_importlib_external.PathFinder 用于导入外部模块,即这用于 mymodule.pymymodule.so。如果我可以用类似的 PathFinder 替换它,它对文件类型使用反向排序,我就会有一个解决方案。

如果这会影响解决方案,我正在使用 Python 3.7。

编辑

请注意,简单地阅读 mymodule.py 的源代码行并执行它们是不行的,因为 mymodule.py可能本身导入其他模块,这些模块再次存在于 .py.so 版本中(我想导入这些的 .py 版本作为好吧)。

最佳答案

这是另一种解决方案,只需调整运行时默认生成的查找器即可。这使用了隐藏的实现细节 (FileFinder._loaders),但我已经在 CPython 3.7、3.8 和 3.9 上进行了测试。

from contextlib import contextmanager
from dataclasses import dataclass
from importlib.machinery import FileFinder
from importlib.abc import Finder
import sys
from typing import Callable


@dataclass
class PreferPureLoaderHook:
    orig_hook: Callable[[str], Finder]

    def __call__(self, path: str) -> Finder:
        finder = self.orig_hook(path)
        if isinstance(finder, FileFinder):
            # Move pure python file loaders to the front
            finder._loaders.sort(key=lambda pair: 0 if pair[0] in (".py", ".pyc") else 1)  # type: ignore
        return finder


@contextmanager
def prefer_pure_python_imports():
    sys.path_hooks = [PreferPureLoaderHook(h) for h in sys.path_hooks]
    sys.path_importer_cache.clear()
    yield
    assert all(isinstance(h, PreferPureLoaderHook) for h in sys.path_hooks)
    sys.path_hooks = [h.orig_hook for h in sys.path_hooks]
    sys.path_importer_cache.clear()

with prefer_pure_python_imports():
    ...

关于Python:强制导入更喜欢 .py 而不是 .so,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56074754/

相关文章:

python - 如何使用 configparser 插入多行值

python - TypeError : __init__() missing 4 required positional arguments:

python - 计算 OOZIE 时间戳差异的最佳方法是什么?

python - 如何在 Python Pandas 中使用逗号作为小数分隔符的浮点格式?

Python 导入迭代,sys.path

ios - 将 ARCharts 框架/项目导入 Swift 项目

带有自动 Prop 和预提交钩子(Hook)的 Svn 导入

python - Tmux 拆分窗口并激活 python virtualenv

python - 如何在 Python 中编写与 Wikipedia 中的示例不同的策略模式?

python - 如何在请求上下文之外伪造 JWT 授权并获取当前身份?