【问题标题】:Dynamic Loading of Python ModulesPython 模块的动态加载
【发布时间】:2010-10-20 15:37:11
【问题描述】:

我正在尝试动态加载我创建的模块。

现在这工作正常:

import structures.index

但是如果我通过动态导入来尝试同样的事情,它会失败。

struct = __import__("structures.index")

提供的错误是:

Error ('No module named structures.index',)

有什么想法吗?


编辑:当使用完整范围时(它有点工作?):

struct = __import__("neoform.structures.index")

这不会引发任何错误,但是,它不会加载索引模块,而是加载“neoform”模块。

“struct”的结果是:

<module 'neoform' from '/neoform/__init__.py'>

另外,作为一个附带问题,我如何在动态加载的模块中实例化一个类? (假设所有模块都包含一个共同的类名)。

编辑:解决方案:(感谢 coonj 和 Rick)这最终是有效的。不知道为什么(还),但fromlist 必须是“显然任何东西,因为当我将字母“a”作为值时它起作用(奇怪,因为文件中只有 1 个类)。

def get_struct_module(self, name):
    try:
        return = __import__("neoform.structures." + name, fromlist='*')
    except ImportError, e:
        self.out.add("Could not load struct: neoform.structure." + name + "\n\n" + "Error " + str(e.args))

【问题讨论】:

  • 一个错误信息会很有用
  • __import__('structures.index') 应该像import structures.index 一样返回对structures 的引用。您遇到什么错误?
  • 错误('没有名为结构的模块',)
  • 并且您确定您有一些文件结构/index.py(并且“导入结构.index”不会因相同的错误而失败?)
  • 是的,这让我很困惑。 “导入结构。索引”有效。 (刚刚在 10 秒前再次测试过。我用它替换了 map(...) 代码..加载得很好。:(

标签: python dynamic module loading


【解决方案1】:

我不确定“失败”是什么意思,所以我只提一下 __import__('structures.index') 实际上应该可以工作,但它不会在当前范围内分配模块名称。为此(然后在动态导入的模块中使用一个类),您必须使用:

structures = __import__('structures.index')
structures.index.SomeClass(...)

__import__ 的完整详细信息可在here 获得。

编辑:(基于问题编辑)

要导入neoform.structures.index,并返回index 模块,您需要执行以下操作:

structures = __import__('neoform.structures.index', 
                        fromlist=['does not in fact matter what goes here!'])

因此,如果您有一个包名称列表packages,您可以导入它们的index 模块并使用以下代码为每个模块实例化一些MyClass 类:

modules = [ __import__('neoform.%s.index' % pkg, fromlist=['a']) 
            for pkg in packages ]
objects = [ m.MyClass() for m in modules ]

【讨论】:

    【解决方案2】:

    要导入子模块,需要在__import__()fromlist arg 中指定它们
    例如,相当于:

    import structures.index
    

    是:

    structures = __import__('structures', fromlist=['index'])
    

    在地图中执行此操作有点棘手...

    import mod1.index
    import mod2.index
    import mod3.index
    

    对于这些导入,您需要定义一个新函数来从每个模块中获取 index 子模块:

    def getIndexMods(mod_names):
      mod_list = map(lambda x: __import__(x, fromlist='index'))
      index_mods = [mod.index for mod in mod_list]
      return index_mods
    

    现在,您可以这样做来获取对所有索引模块的引用:

    index_mods = getIndexMods(['mod1', 'mod2', 'mod3'])
    

    此外,如果您想获取未命名为“索引”的子模块,那么您可以这样做:

    mod1, mod2, mod3 = map(lambda x,y: __import__(x, fromlist=y), 
      ['mod1', 'mod2', 'mod3'], ['index1', 'index2', 'index3'])
    

    【讨论】:

    • 实际上不需要使用fromlist来导入子模块;试试“__import__('os.path')”。工作得很好(尽管它返回 os,而不是 os.path。) fromlist 模拟“从 os 导入路径”,这是一个不同的野兽。
    • 这样做可以工作结构 = __import__('structures') 但是 fromlist 部分不返回模块,而是返回父“结构”。 :(
    • 你怎么称呼它?也许你想这样做?:从结构导入索引
    • 我更新了我的答案,并根据您在其他答案上留下的 o cmets 做了一些假设。
    【解决方案3】:

    通过此辅助方法使用完整范围(“neoform.structures.index”)。

    def import_module(name):
        mod = __import__(name)
        components = name.split('.')
        for comp in components[1:]:
            mod = getattr(mod, comp)
        return mod
    
    module = import_module("neoform.structures.index")
    # do stuff with module
    

    【讨论】:

      【解决方案4】:

      Java 程序员在这里,但我认为你需要 imp module

      【讨论】:

      • 刚刚注意到 import 使用 imp 模块的实现;谢谢:)
      【解决方案5】:
      >>> import imp
      >>> fm = imp.find_module('index', ['./structures']) # for submodule
      >>> mymod = imp.load_module('structures.index', *fm)
      >>> mymod
      <module 'structures.index' from './structures/index.pyc'>
      >>> x = mymod.insideIndex()
      Initialising index class...
      

      瞧!

      【讨论】:

        【解决方案6】:

        你为什么要替换

        import structures.index
        

        map(__import__, ["structures.index"])
        

        第一个(a)有效,(b)动态的,(c)直接支持。有什么可能的用例可以用更复杂的东西替换易于更改的纯文本源?

        简而言之:不要这样做。它没有任何价值。


        编辑

        “我正在从数据库获取导入”是一项崇高的努力,但仍然不明智。哪些代码块取决于这些导入?整个代码块——导入和所有——就是你想要执行的。整个代码块——导入、语句和所有东西——应该是一个普通的旧 python 模块文件。

        从文件系统中导入该代码块。使用数据库来识别哪个文件,文件的作者——任何你想使用数据库的东西。但只需以最简单的方式导入并执行模块。

        【讨论】:

        • 我猜他想动态导入多个模块。伊恩?对此有何回应?
        • 而“动态”我假设 Ian 的意思是他直到运行时才知道他正在导入什么。
        • 我这样做是因为字符串将是从数据库调用的变量。我只是使用字符串来简化示例。
        • 那会很烦人。我将它存储在数据库中的原因是因为我正在制作一个 mod_wsgi 站点。每个模块都是站点上的一个单独页面。我已经用 PHP 做过这种事情,并且我在某些网站上有 300 多个结构,每个结构都有自己的层次结构、权限和其他属性。将其存储在数据库中是我发现的最佳方式。
        • @Ian:Python 不是 PHP。适用于 PHP 的技术并不总是转化为 Python。我认为你正在做的事情对 Python 来说不会很好。查看 TurboGears 或 web.py 以了解如何在 Python 中执行此操作的示例。
        【解决方案7】:

        在这里发帖真的很晚。但我在谷歌上搜索这个问题。我做了一些试验和错误。不确定这个 sn-p 是否有帮助,但它就在这里。将其用于 Flask 站点。

        modules = ['frontend', 'admin']
        for module in modules:
            mod = __init__('controllers.%s' % module, fromlist=[module])
            app.register_blueprint(mod.blueprint_mod)
        
        
        # or
        from importlib import import_module
        modules = ['frontend', 'admin']
        for module in modules:
            mod = import_module('controllers.%s' % module)
            app.regitster_blueprint(mod.blueprint_mod)
        

        【讨论】:

          猜你喜欢
          • 2010-10-31
          • 2011-05-13
          • 2011-01-11
          • 2013-11-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多