关于python和__import__的问题

1 投票
3 回答
3771 浏览
提问于 2025-04-15 13:54

抱歉标题有点普通,等我搞清楚问题的来源再改。

我有以下的结构:

foo/
foo/__init__.py
foo/bar/
foo/bar/__init__.py
foo/bar/some_module.py

当我尝试通过下面的方式导入某个模块时:

from foo.bar import some_module

这就能顺利运行。

但这样对我来说不太好,因为我只能在运行时知道要导入哪个模块。所以如果我尝试:

from foo.bar import *
mod=__import__('some_module')

我就会遇到错误。我是不是做错了什么?有没有更好的方法?为什么会这样?

这是为什么呢?我不太确定我完全理解Python包的概念。我原以为它们和Java的包是一样的,所以……

3 个回答

0

来自文档的内容:

直接使用__import__()的情况很少,通常只有在你想导入一个名字在运行时才知道的模块时才会用到。

不过,使用点号的方式应该是可以的:

mod = __import__('foo.bar.some_module')
1
from foo.bar import *

这样做是不好的习惯,因为它把 some_module 导入到了全局范围内。

你应该通过以下方式来访问你的模块:

import foo.bar
mod = getattr(foo.bar, 'some_module')

这个方法的有效性很容易证明:

>>> import os.path
>>> getattr(os.path, 'basename')
<function basename at 0x00BBA468>
>>> getattr(os.path, 'basename\n')
Traceback (most recent call last):
  File "<pyshell#31>", line 1, in <module>
    getattr(os.path, 'basename\n')
AttributeError: 'module' object has no attribute 'basename
'

附言:如果你仍然想使用你那种导入语句,你需要用到 eval

from foo.bar import *
eval('some_module')

为了说明:不仅仅是使用 * 导入是不好的习惯,和 eval 一起使用更是糟糕。所以就用 getattr 吧,它正是为你这种情况设计的。

7

我认为正确的做法是:

mod = __import__('foo.bar', fromlist = ['some_module'])

这样做的话,即使是 'foo.bar' 这一部分也可以在运行时进行更改。 这样一来,some_module 就可以作为 mod.some_module 来使用;如果你想把它放在一个单独的变量里,可以使用 getattr:

the_module = getattr(mod, 'some_module')

撰写回答