【问题标题】:Alternatives to imp.find_module?imp.find_module 的替代品?
【发布时间】:2011-08-10 03:02:34
【问题描述】:

背景

当您使用命名空间包并将代码库划分为单独的文件夹时,我已经厌倦了 pylint 无法导入文件的问题。因此,我开始深入研究已被确定为问题根源的 astNG 源代码(请参阅关于 astng 的错误报告8796)。问题的核心似乎是在查找导入的过程中使用了 python 自己的 imp.find_module

会发生什么情况是导入的第一个(子)包 - import a.b.c 中的 a - 使用 None 路径馈送到 find_module。无论返回什么路径,然后都会将其输入到find_module 中的下一个查找循环中,您尝试在前面的示例中找到b

来自 logilab.common.modutils 的伪代码:

path = None
while import_as_list:
      try:
           _, found_path, etc = find_module(import_as_list[0], path)
      #exception handling and checking for a better version in the .egg files
      path = [found_path]
      import_as_list.pop(0)

问题

这就是问题所在:您只能从find_module 获得最佳点击,其中可能包含也可能不包含您的子包。如果您没有找到子包,则无法退出并尝试下一个。

我尝试显式使用 sys.path 而不是 None,以便可以从路径列表中删除结果并进行第二次尝试,但是 python 的模块查找器足够聪明,不需要完全匹配在路径中,使这种方法无法使用 - 据我所知。

泪眼恳求

是否有替代 find_modules 的方法,它将返回 ALL 可能的匹配项或获取排除列表?我也对完全不同的解决方案持开放态度。最好不要手动修补 python,但这并非不可能——至少对于本地解决方案而言。

(请注意:我正在运行 python 2.6,由于当前的公司政策无法升级,p3k 等的建议不会被标记为已接受,除非这是唯一的答案。)

【问题讨论】:

    标签: python namespaces importerror pylint


    【解决方案1】:

    我也厌倦了 PyLint 中的这种限制。

    我不知道 imp.find_modules() 的替代品,但我想我找到了另一种在 PyLint 中处理命名空间包的方法。请参阅我对您链接到的错误报告的评论 (http://www.logilab.org/ticket/8796)。

    这个想法是使用 pkg_resources 来查找命名空间包。这是我对logilab.common.modutils._module_file() 的补充,就在while modpath 之后:

      while modpath:
          if modpath[0] in pkg_resources._namespace_packages and len(modpath) > 1:
              module = sys.modules[modpath.pop(0)]
              path = module.__path__
    

    这不是很精致,但只处理顶级命名空间包。

    【讨论】:

    • 顶级命名空间包足以满足我的需求,我真的希望这(或更一般的东西)能尽快融入源代码!我很高兴你设法找到了我画一个空白的修复:)
    【解决方案2】:

    从 Python 2.5 开始,正确的做法是使用 pkgutil.iter_modules()(用于平面列表)或 pkgutil.walk_packages()(用于子包树)。两者都与命名空间包完全兼容。

    例如,如果我只想找到 'jmb' 的子包/子模块,我会这样做:

    import jmb, pkgutil
    for (module_loader, name, ispkg) in pkgutil.iter_modules(jmb.__path__, 'jmb.'):
        # 'name' will be 'jmb.foo', 'jmb.bar', etc.
        # 'ispkg' will be true if 'jmb.foo' is a package, false if it's a module
    

    您也可以使用 iter_modules 或 walk_packages 遍历 所有 sys.path 上的模块;有关详细信息,请参阅上面链接的文档。

    【讨论】:

      【解决方案3】:

      警告+免责声明:尚未测试!

      之前:

      for part in parts:
          modpath.append(part)
          curname = '.'.join(modpath)
          # ...
          if module is None:
              mp_file, mp_filename, mp_desc = imp.find_module(part, path)
              module = imp.load_module(curname, mp_file, mp_filename, mp_desc)
      

      之后: - 感谢pjeby 提及pkgutil

      for part in parts:
          modpath.append(part)
          curname = '.'.join(modpath)
          # ...
          if module is None:
              # + https://stackoverflow.com/a/14820895/611007
              # # mp_file, mp_filename, mp_desc = imp.find_module(part, path)
              # # module = imp.load_module(curname, mp_file, mp_filename, mp_desc)
              import pkgutil
              mp_file = None
              for loadr,name,ispkg in pkgutil.iter_modules(path=path,prefix='.'.join(modpath[:-1])+'.'):
                  if name.split('.')[-1] == part:
                      if not hasattr(loadr,'path') and hasattr(loadr,'archive'):
                          # with zips `name` was like '.somemodule'
                          # it gives `RuntimeWarning: Parent module '' not found while handling absolute import`
                          # I expect the name I need to be 'somemodule'
                          # TODO: I don't know why python does this or what the correct usage is.
                          # https://stackoverflow.com/questions/2267984/
                          if name and name[0] == '.':
                              name = name[1:]
                          ldr= loadr.find_module(name,loadr.archive)
                          module = ldr.load_module(name)
                          break
                      imploader= loadr.find_module(name,loadr.path)
                      mp_file,mp_filename,mp_desc= imploader.file,imploader.filename,imploader.etc
                      module = imploader.load_module(imploader.fullname)
                      break
              if module is None:
                  raise ImportError
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-11-08
        • 2012-01-25
        • 2015-08-05
        • 2011-01-01
        • 2011-10-24
        相关资源
        最近更新 更多