为什么Python的__import__需要fromlist?

时间:2010-04-27 19:15:22

标签: python python-import

在Python中,如果要以编程方式导入模块,可以执行以下操作:

module = __import__('module_name')

如果你想导入一个子模块,你会认为它只是一个简单的问题:

module = __import__('module_name.submodule')

当然,这不起作用;你再次获得module_name。你必须这样做:

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

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

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

3 个答案:

答案 0 :(得分:121)

事实上,__import__()的行为完全是因为调用import的{​​{1}}语句的实现。 __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

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

__import__()

但是,如果tmp = __import__('pkg') mod = tmp.mod mod2 = tmp.mod2 是一个包而pkgmod是该包中尚未导入的模块,则无效他们处于第三和第五种情况。 mod2函数需要知道__import__()modmod2语句要访问的名称,以便它可以查看它们是否为模块并尝试也导入它们。所以电话更接近:

import

导致tmp = __import__('pkg', fromlist=['mod', 'mod2']) mod = tmp.mod mod2 = tmp.mod2 尝试加载__import__()pkg.mod以及pkg.mod2(但如果pkgmod不加载mod2存在,它不是__import__()调用中的错误;产生错误留给import语句。)但是对于第四和第五个例子来说仍然不是正确的,因为如果调用是这样的:

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

然后tmp将像以前一样成为pkg,而不是pkg.mod模块,您想从中获取submod属性。实现可能已经决定使import语句执行额外的工作,将.上的包名称与已经执行的__import__()函数分开并遍历名称,但这意味着重复一些努力。相反,实现__import__()返回最右侧模块而不是最左侧一个当且仅当时fromlist被传递而不是空。

import pkg as pfrom pkg import mod as m语法不会更改此故事的任何内容,除了分配了哪些本地名称 - __import__()函数在as时看不到任何不同使用时,它都保留在import语句实现中。)

答案 1 :(得分:5)

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

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

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

现在A是packageBCmodule。所以当我们在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']

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

答案 2 :(得分:2)

答案可以在__import__的文档中找到:

  

fromlist应该是要模拟from name import ...的名称列表,要么是用来模拟import name的空列表。

     

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

基本上,这就是__import__的实现如何工作:如果你想要子模块,你传递一个fromlist包含你要从子模块导入的东西,以及{{1这样就会返回子模块。

进一步说明

我认为存在语义,以便返回最相关的模块。换句话说,我说包含__import__的包foo包含函数bar。如果我:

baz

然后我将import foo.bar 称为

baz

这就像foo.bar.baz()

如果我导入:

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

然后我将from foo import bar 称为     bar.baz()

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>仍然是最具体的模块。返回。