为什么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
语句应该将“最左”的模块对象分配给“最左”的名称: 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__()
函数需要知道mod
和mod2
是import
语句将要访问的名称,以便它可以查看它们是否是模块并尝试导入它们。 所以这个电话接近:
tmp = __import__('pkg', fromlist=['mod', 'mod2']) mod = tmp.mod mod2 = tmp.mod2
这导致__import__()
尝试加载pkg.mod
和pkg.mod2
以及pkg
(但是如果mod
或mod2
不存在,它不是__import__()
调用中的错误;生成一个错误留给import
声明)。但是对于第四个和第五个例子来说,这仍然不是正确的,因为如果这个呼叫是这样的话:
tmp = __import__('pkg.mod', fromlist=['submod']) submod = tmp.submod
那么tmp
会像以前一样成为pkg
,而不是您想要从中获取submod
属性的pkg.mod
模块。 实现可能已经决定做这个,所以import
语句做了额外的工作,把包名分开.
就像__import__()
函数已经做的那样遍历这些名字,但是这意味着重复了一些工作。 所以,相反,实现使__import__()
返回最右边的模块,而不是最左边的模块, 当且仅当 fromlist被传递而不是空的。
( import pkg as p
和from pkg import mod as m
语法并没有改变关于这个故事的任何内容,除了哪些本地名被赋值 – 当使用__import__()
函数时没有什么区别,它们都保留在import
语句实现。)
当我阅读答案时,我仍然感到奇怪,所以我尝试了下面的代码示例。
首先,尝试构build下面的文件结构:
tmpdir |A |__init__.py | B.py | C.py
现在A是一个package
, B
或C
是一个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
仍然是最具体的模块。