【问题标题】:imp.find_module() which supports zipped eggsimp.find_module() 支持压缩鸡蛋
【发布时间】:2015-03-10 11:19:37
【问题描述】:

imp.find_module() 没有从压缩鸡蛋中找到模块。

如何找到可以来自两个地方的模块:目录或压缩鸡蛋?在我的情况下,重要的是我可以提供像 imp.find_module() 这样的 path 参数支持它。

背景

不知何故,软件包在我们的环境中安装了两次。作为压缩鸡蛋和普通文件。我想写一个检查,告诉我一个模块是否安装了两次。见https://stackoverflow.com/a/23990989/633961

【问题讨论】:

  • 如果您的模块位于压缩鸡蛋内的包层次结构的深处怎么办?在这种情况下你想要什么路径? 没有文件直接等同于您请求的模块。
  • @Kevin imp.find_module() 仅查找“顶级”模块。例如,您可以找到“os”,但找不到“path”(例如来自“os.path”)。我只想要一个像 python 解释器的 import 语句一样工作的 find_module() 。解释器加载压缩鸡蛋。
  • 2.x 中的导入机制暴露不完全。在 3.x 下,你可以通过importlib 得到你想要的; imp 已弃用。不幸的是,这也意味着整个事情比以前的imp 要复杂得多。
  • @Kevin 谢谢你的提示。 importlib 即使在 Python2.7 中也存在。它是一个子集,但总比没有好。

标签: python python-import


【解决方案1】:

假设 Python 2,我认为您需要的信息在 PEP 302 - New Import Hooks 中(PEP 对于 Python 3 已经过时,在这方面完全不同)。

从 ZIP 档案中查找和导入模块在 zipimport 中实现,它被“挂钩”到 PEP 所描述的导入机制中。当 PEP 302 和从 ZIP 导入被添加到 Python 时,imp 模块没有被适配,即imp 完全不知道 PEP 302 钩子。

一个“通用”find_module 函数可以找到像 imp 这样的模块,并且并且尊重 PEP 302 钩子,大致如下所示:

import imp
import sys

def find_module(fullname, path=None):
    try:
        # 1. Try imp.find_module(), which searches sys.path, but does
        # not respect PEP 302 import hooks.
        result = imp.find_module(fullname, path)
        if result:
            return result
    except ImportError:
        pass
    if path is None:
        path = sys.path
    for item in path:
        # 2. Scan path for import hooks. sys.path_importer_cache maps
        # path items to optional "importer" objects, that implement
        # find_module() etc.  Note that path must be a subset of
        # sys.path for this to work.
        importer = sys.path_importer_cache.get(item)
        if importer:
            try:
                result = importer.find_module(fullname, [item])
                if result:
                    return result
            except ImportError:
                pass
    raise ImportError("%s not found" % fullname)

if __name__ == "__main__":
    # Provide a simple CLI for `find_module` above.
    import argparse
    parser = argparse.ArgumentParser()
    parser.add_argument("-p", "--path", action="append")
    parser.add_argument("modname", nargs='+')
    args = parser.parse_args()
    for name in args.modname:
        print find_module(name, args.path)

但请注意,在 ZIP 存档中查找模块的结果与 imp.find_module 返回的结果完全不同:您将获得特定 ZIP 的 zipimport.zipimporter 对象。当要求查找常规模块、内置模块和压缩鸡蛋中的模块时,上面的小程序会打印以下内容:

$ python find_module.py grin os sys
<zipimporter object "<my venv>/lib/python2.7/site-packages/grin-1.2.1-py2.7.egg">
(<open file '<my venv>/lib/python2.7/os.py', mode 'U' at 0x10a0bbf60>, '<my venv>/lib/python2.7/os.py', ('.py', 'U', 1))
(None, 'sys', ('', '', 6))

【讨论】:

  • importer.find_module(fullname) 的调用没有传递path 参数。如果路径不是 sys.path,这会导致返回错误结果
  • 我已经更新了代码。现在它将正确地尊重path。我的意思是解释发生了什么。
  • 您将path 传递给importer.find_modul()。但是AFAIK参数path被zipimporter忽略了:-(
  • 是的,我知道zipimporter 忽略了它。但是可能安装了 other 使用path 的导入挂钩。到目前为止,我的回答更广泛地解决了您的问题,因为代码将找到 Python 解释器以类似于真正的import 实现的方式找到的任何模块(以 import.c、PEP 302 等的复杂相互作用所带来的困难为模。在 Python 2) 中。
猜你喜欢
  • 2010-11-16
  • 2011-01-02
  • 2015-05-20
  • 2017-03-08
  • 1970-01-01
  • 1970-01-01
  • 2016-03-03
  • 1970-01-01
  • 2017-02-28
相关资源
最近更新 更多