Python的__import__不按预期工作

44 投票
6 回答
20027 浏览
提问于 2025-04-11 09:34

当你使用 __import__ 这个函数,并且给它一个带点的名字,比如说 somepackage.somemodule,你会发现返回的模块并不是 somemodule,而是看起来几乎是空的东西!这是怎么回事呢?

6 个回答

16

这里有一个更简单的解决办法,文档里有解释:

如果你只是想通过名字导入一个模块(可能是在一个包里面),你可以使用 __import__() 函数,然后在 sys.modules 里查找它:

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

Python 2.7 有一个叫做 importlib 的模块,它可以按照预期处理带点的路径。

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

来自Python文档关于__import__的内容:

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

...

当你使用的名字是类似于 package.module的格式时,通常会返回 顶层包(也就是第一个点之前的名字),而不是 名字所指的模块。不过,当你提供了一个 非空的fromlist参数时,就会返回 名字所指的模块。这是为了和 不同类型的导入语句生成的字节码兼容; 比如,当你使用“import spam.ham.eggs”时, 顶层包spam必须放在导入的命名空间中,但 当你使用“from spam.ham import eggs”时, 就必须使用spam.ham子包来找到 eggs变量。为了应对这种情况,可以使用 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

你也可以像我一样,使用他们建议的函数。

注意:我问这个问题时,完全是打算自己回答的。我的代码里有一个大bug,我误诊了它,花了很长时间才搞明白,所以我想帮助一下SO社区,把我遇到的问题分享出来。

撰写回答