【问题标题】:Python's __import__ doesn't work as expectedPython 的 __import__ 不能按预期工作
【发布时间】:2025-11-30 11:50:01
【问题描述】:

当使用带点名称的__import__ 时,例如:somepackage.somemodule,返回的模块不是somemodule,返回的内容似乎大部分都是空的!这是怎么回事?

【问题讨论】:

    标签: python python-import


    【解决方案1】:

    来自__import__ 上的 python 文档:

    __import__( name[, globals[, locals[, fromlist[, level]]]])
    

    ...

    当名称变量的形式为 package.module,通常是 *包(名称直到 返回第一个点),而不是 以名称命名的模块。然而,当一个 给出了非空的 fromlist 参数, 返回以名称命名的模块。 这样做是为了兼容 为 不同种类的进口声明; 使用“import spam.ham.eggs”时, 必须放置*包垃圾邮件 在导入命名空间中,但是当 使用“从 spam.ham 导入鸡蛋”, spam.ham 子包必须用于 找到鸡蛋变量。作为一个 此行为的解决方法,使用 getattr() 提取所需的 组件。例如,您可以 定义以下助手:

    def my_import(name):
        mod = __import__(name)
        components = name.split('.')
        for comp in components[1:]:
            mod = getattr(mod, comp)
        return mod
    

    转述:

    当您请求somepackage.somemodule 时,__import__ 返回somepackage.__init__.py,通常为空。

    如果你提供fromlist,它将返回somemodule(你想要的somemodule中的变量名列表,实际上并没有返回)

    您也可以像我一样使用他们建议的功能。

    注意:我问这个问题完全是想自己回答。我的代码中有一个大错误,并且被误诊了,我花了很长时间才弄明白,所以我想我会帮助 SO 社区并在这里发布我遇到的问题。

    【讨论】:

      【解决方案2】:

      python 2.7 有 importlib,虚线路径按预期解析

      import importlib
      foo = importlib.import_module('a.dotted.path')
      instance = foo.SomeClass()
      

      【讨论】:

      【解决方案3】:

      有一个更简单的解决方案,如文档中所述:

      如果您只是想按名称导入模块(可能在包中),您可以调用 __import__() 然后在 sys.modules 中查找它:

      >>> import sys
      >>> name = 'foo.bar.baz'
      >>> __import__(name)
      <module 'foo' from ...>
      >>> baz = sys.modules[name]
      >>> baz
      <module 'foo.bar.baz' from ...>
      

      【讨论】:

        【解决方案4】:

        有些东西可以按你的意愿工作:twisted.python.reflect.namedAny:

        >>> from twisted.python.reflect import namedAny
        >>> namedAny("operator.eq")
        <built-in function eq>
        >>> namedAny("pysqlite2.dbapi2.connect")
        <built-in function connect>
        >>> namedAny("os")
        <module 'os' from '/usr/lib/python2.5/os.pyc'>
        

        【讨论】:

        • 这非常有用,但是我的程序中并没有任何其他需要扭曲的东西。虽然,作为创始人(!),您可能比我更了解可能性(从未使用过)。
        【解决方案5】:

        对于python 2.6,我写了这个sn-p:

        def import_and_get_mod(str, parent_mod=None):
            """Attempts to import the supplied string as a module.
            Returns the module that was imported."""
            mods = str.split('.')
            child_mod_str = '.'.join(mods[1:])
            if parent_mod is None:
                if len(mods) > 1:
                    #First time this function is called; import the module
                    #__import__() will only return the top level module
                    return import_and_get_mod(child_mod_str, __import__(str))
                else:
                    return __import__(str)
            else:
                mod = getattr(parent_mod, mods[0])
                if len(mods) > 1:
                    #We're not yet at the intended module; drill down
                    return import_and_get_mod(child_mod_str, mod)
                else:
                    return mod
        

        【讨论】:

          【解决方案6】:

          我的做法是

          foo = __import__('foo',  globals(), locals(), ["bar"], -1)
          foobar = eval("foo.bar")
          

          然后我可以访问任何来自

          的内容
          foobar.functionName()
          

          【讨论】: