2010-04-27 81 views
67

在Python中,如果你想以编程方式导入一个模块,你可以这样做:为什么Python的__import__需要fromlist?

module = __import__('module_name') 

如果要导入一个子模块,你会觉得这是一个简单的问题:

module = __import__('module_name.submodule') 

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

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

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

Python中的大部分内容似乎都是出于很好的理由完成的,但对于我的生活而言,我无法想出任何合理的解释来解释这种行为的存在。

回答

116

实际上,__import__()的行为完全是因为执行了import语句,该语句调用__import__()。有基本上5种略微不同的方式__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是一个包和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,和以前一样,而不是pkg.mod模块,你想从中获得submod属性。这个实现可能已经决定了,所以import声明做了额外的工作,在.上拆分了包名,就像__import__()函数已经做过的那样,并且遍历了这些名字,但是这意味着重复了一些工作。所以,相反,执行方面__import__()回报最右边模块代替最左边一个当且仅当 fromlist里传递,而不是空。

(该import pkg as pfrom pkg import mod as m语法不改变这个故事,除了其本地的名字会被分配到任何东西 - 在__import__()功能看没啥区别在使用as,这一切仍然在import语句执行。)

2

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

fromlist里应该是名称的列表效仿from name import ...,或空单效仿import name

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

因此,基本上,这就是__import__作品是如何实现:如果你想子模块,你传递一个你想从子模块导入包含fromlist的东西,如果__import__实施使得返回子模块。

进一步解释

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

import foo.bar 

然后我指的是baz作为

foo.bar.baz() 

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

相反,如果我用导入:

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>语法导入模块,在这种情况下,bar仍然是最具体的模块返回。

+0

说“这只是实施的工作原理”并不能回答我的问题。它为什么这样工作? 说“模仿从名称导入...”形式更接近,但在什么情况下你会需要吗? fromlist不会影响__import__的实际工作方式,所以我没有看到有什么情况需要通过它来模拟任何事情,除了该函数明显的行为。 – ieure 2010-04-27 19:33:21

+1

你是对的,这是乞讨的问题。我更新了我的答案以提供更相关的答复。 – mipadi 2010-04-27 20:31:43

4

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

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

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

现在是package,并BCmodule。所以,当我们试图像这样的一些代码在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使用fromlist里,而不是package,因为module已编制fromlist里PARAM没有帮助的。一旦它被导入,就没有办法忽略其他的。