为什么Python的__import__需要fromlist?

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

module = __import__('module_name') 

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

 module = __import__('module_name.submodule') 

当然,这是行不通的。 你只需再次获取module_name 。 你必须做:

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

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

Python中的大部分东西似乎都是有原因的,但是对于我来说,我无法想出任何合理的解释。

实际上, __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语句应该将“最左”的模块对象分配给“最左”的名称: pkgimport 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是一个包,并且modmod2是该包中尚未导入的模块,那么这将不起作用 ,因为它们是第三种情况和第五种情况。 __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 ,而不是您想要从中获取submod属性的pkg.mod模块。 实现可能已经决定做这个,所以import语句做了额外的工作,把包名分开. 就像__import__()函数已经做的那样遍历这些名字,但是这意味着重复了一些工作。 所以,相反,实现使__import__()返回最右边的模块,而不是最左边的模块, 当且仅当 fromlist被传递而不是空的。

import pkg as pfrom pkg import mod as m语法并没有改变关于这个故事的任何内容,除了哪些本地名被赋值 – 当使用__import__()函数时没有什么区别,它们都保留在import语句实现。)

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

首先,尝试构build下面的文件结构:

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

现在A是一个packageBC是一个module 。 所以当我们在ipython中尝试一些这样的代码时:

其次,在ipython中运行示例代码:

  In [2]: kk = __import__('A',fromlist=['B']) In [3]: dir(kk) Out[3]: ['B', '__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__'] 

看起来像从我们预期的名单。 但是当我们试图在一个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'] 

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

答案可以在以下文件中__import____import__

fromlist应该是from name import ...中模拟的import name列表,或者是一个空列表来模拟import name

从包中导入模块时,请注意__import__('A.B', ...)在fromlist为空时返回程序包A,但fromlist中的子模块B不为空时返回。

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

进一步解释

我认为存在这样的语义,以便返回最相关的模块。 也就是说,我有一个包含functionbaz模块bar foo包。 如果我:

 import foo.bar 

那么我把baz称为

 foo.bar.baz() 

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

如果我input:

 from foo import bar 

那么我把baz称为bar.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>语法来from <package> import <module> ,在这种情况下, bar仍然是最具体的模块。