80

在 Python 中,如果你想以编程方式导入一个模块,你可以这样做:

module = __import__('module_name')

如果要导入子模块,您会认为这很简单:

module = __import__('module_name.submodule')

当然,这是行不通的;你module_name又来了。你所要做的:

module = __import__('module_name.submodule', fromlist=['blah'])

为什么?的实际值fromlist似乎根本不重要,只要它不为空即可。要求一个论点,然后忽略它的价值有什么意义?

Python 中的大多数东西似乎都是有充分理由的,但对于我的一生,我无法为这种行为的存在提出任何合理的解释。

4

3 回答 3

134

事实上, 的行为__import__()完全是因为执行了import语句,它调用了__import__(). 基本上有五种略有不同的__import__()调用方式import(有两个主要类别):

import pkg
import pkg.mod
from pkg import mod, mod2
from pkg.mod import func, func2
from pkg.mod import submod

在第一种第二种情况下,import语句应该将“最左边”模块对象分配给“最左边”名称:pkg. 之后import pkg.mod可以做pkg.mod.func()因为import语句引入了本地名称pkg,这是一个具有mod属性的模块对象。因此,该__import__()函数必须返回“最左侧”模块对象,以便将其分配给pkg. 因此,这两个 import 语句转换为:

pkg = __import__('pkg')
pkg = __import__('pkg.mod')

在第三种、第四种和第五种情况下,该import语句必须做更多的工作:它必须分配(可能)多个名称,这些名称必须从模块对象中获取。该__import__()函数只能返回一个对象,并且没有真正的理由让它从模块对象中检索这些名称中的每一个(这会使实现变得更加复杂。)所以简单的方法类似于(对于第三个案子):

tmp = __import__('pkg')
mod = tmp.mod
mod2 = tmp.mod2

但是,如果pkg是一个包,mod或者是该包中尚未导入mod2的模块,这将不起作用,因为它们在第三种和第五种情况下。该函数需要知道这一点,并且是语句希望可以访问的名称,以便它可以查看它们是否是模块并尝试导入它们。所以调用更接近:__import__()modmod2import

tmp = __import__('pkg', fromlist=['mod', 'mod2'])
mod = tmp.mod
mod2 = tmp.mod2

这导致__import__()尝试加载pkg.modpkg.mod2以及pkg(但如果modmod2不存在,这不是__import__()调用中的错误;产生错误留给import语句。)但这仍然不是第四个和正确的事情第五个例子,因为如果调用是这样的:

tmp = __import__('pkg.mod', fromlist=['submod'])
submod = tmp.submod

那么tmp最终会pkg像以前一样,而不是pkg.mod您要从中获取submod属性的模块。实现可能已经决定这样做,因此import语句做了额外的工作,.__import__()函数已经做的那样拆分包名称并遍历名称,但这意味着重复一些工作。因此,当且仅当fromlist 被传递且不为空时,实现__import__()返回最右边模块而不是最左边的模块。

import pkg as pandfrom pkg import mod as m语法并没有改变这个故事的任何内容,除了分配了哪些本地名称 - 该__import__()函数在as使用时没有任何不同,它都保留在import语句实现中。)

于 2010-04-27T22:39:46.583 回答
7

当我阅读答案时我仍然觉得很奇怪,所以我尝试了下面的代码示例。

首先,尝试构建以下文件结构:

tmpdir
  |A
     |__init__.py
     | B.py
     | C.py

现在 A 是 a package,并且BorC是 a module。所以当我们在 ipython 中尝试这样的代码时:

二、在ipython中运行示例代码:

  In [2]: kk = __import__('A',fromlist=['B'])

  In [3]: dir(kk)
  Out[3]: 
  ['B',
   '__builtins__',
   '__doc__',
   '__file__',
   '__name__',
   '__package__',
   '__path__']

看起来 fromlist 就像我们预期的那样工作。但是当我们尝试在module. 假设我们有一个名为 C.py 的模块和其中的代码:

  handlers = {}

  def hello():
      print "hello"

  test_list = []

所以现在我们尝试在它上面做同样的事情。

  In [1]: ls
  C.py

  In [2]: kk = __import__('C')

  In [3]: dir(kk)
  Out[3]: 
  ['__builtins__',
   '__doc__',
   '__file__',
   '__name__',
   '__package__',
   'handlers',
   'hello',
   'test_list']

那么当我们只想导入 test_list 的时候,它有效吗?

  In [1]: kk = __import__('C',fromlist=['test_list'])

  In [2]: dir(kk)
  Out[2]: 
  ['__builtins__',
   '__doc__',
   '__file__',
   '__name__',
   '__package__',
   'handlers',
   'hello',
   'test_list']

结果表明,当我们尝试在 amodule而不是 a上使用 fromlist 时package, fromlist 参数根本没有帮助,因为module已经编译了。一旦导入,就无法忽略其他的。

于 2013-04-10T03:15:12.873 回答
4

答案可以在以下文档中找到__import__

fromlist 应该是要模拟的名称列表from name import ...,或者是要模拟的空列表import name

从包中导入模块时,注意__import__('A.B', ...)当 fromlist 为空时返回包 A,但当 fromlist 不为空时返回其子模块 B。

所以基本上,这就是实现的__import__工作方式:如果你想要子模块,你传递一个fromlist包含你想从子模块导入的东西,并且实现 if__import__是这样的,即返回子模块。

进一步说明

我认为语义存在以便返回最相关的模块。换句话说,假设我有一个包含具有功能foo的模块的包。如果我:barbaz

import foo.bar

然后我baz称之为

foo.bar.baz()

这就像__import__("foo.bar", fromlist=[]).

相反,如果我导入:

from foo import bar

然后我称之为bazbar.baz()

这将类似于__imoort__("foo.bar", fromlist=["something"]).

如果我做:

from foo.bar import baz

然后我baz称之为

baz()

这就像__import__("foo.bar", fromlist=["baz"]).

所以在第一种情况下,我必须使用完全限定名称,因此__import__返回您用来引用导入元素的第一个模块名称,即foo. 在最后一种情况下,是包含导入元素的最具体的模块,因此返回模块bar是有意义的。__import__foo.bar

第二种情况有点奇怪,但我猜它是这样编写的,以支持使用from <package> import <module>语法导入模块,在这种情况下bar仍然是要返回的最具体的模块。

于 2010-04-27T19:20:31.010 回答