为什么Python的__import__需要fromlist?

ieu*_*ure 74 python python-import

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

module = __import__('module_name')
Run Code Online (Sandbox Code Playgroud)

如果要导入子模块,您会认为这只是一个简单的问题:

module = __import__('module_name.submodule')
Run Code Online (Sandbox Code Playgroud)

当然,这不起作用; 你module_name再来一次 你必须做:

module = __import__('module_name.submodule', fromlist=['blah'])
Run Code Online (Sandbox Code Playgroud)

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

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

Tho*_*ers 124

实际上,行为__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
Run Code Online (Sandbox Code Playgroud)

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

pkg = __import__('pkg')
pkg = __import__('pkg.mod')
Run Code Online (Sandbox Code Playgroud)

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

tmp = __import__('pkg')
mod = tmp.mod
mod2 = tmp.mod2
Run Code Online (Sandbox Code Playgroud)

但是,如果pkg是一个包和/ modmod2该包中尚未导入的模块,那将无法工作,因为它们在第三和第五种情况下.该__import__()函数需要知道该语句mod并且mod2是该import语句可以访问的名称,以便它可以查看它们是否是模块并尝试导入它们.所以电话更接近:

tmp = __import__('pkg', fromlist=['mod', 'mod2'])
mod = tmp.mod
mod2 = tmp.mod2
Run Code Online (Sandbox Code Playgroud)

这会导致__import__()尝试和负载pkg.modpkg.mod2以及pkg(但如果mod还是mod2不存在,它不是在错误__import__()的呼叫;产生一个错误是留给import声明.)但是,这还不是第四和正确的事第五个例子,因为如果这样的话:

tmp = __import__('pkg.mod', fromlist=['submod'])
submod = tmp.submod
Run Code Online (Sandbox Code Playgroud)

然后tmppkg像以前那样结束,而不是pkg.mod你想从中获取submod属性的模块.实现可能已经决定这样使它import语句做额外的工作,对在将包名.状的__import__()功能已经不和穿越的名字,但是这将意味着重复了一些努力.所以,相反,执行方面取得__import__()返回最右边的模块,而不是最左边的一个当且仅当 fromlist里传递,而不是空.

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


zhk*_*yth 5

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

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

tmpdir
  |A
     |__init__.py
     | B.py
     | C.py
Run Code Online (Sandbox Code Playgroud)

现在A是a package,B或者C是a module.所以当我们在ipython中尝试这些代码时:

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

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

  In [3]: dir(kk)
  Out[3]: 
  ['B',
   '__builtins__',
   '__doc__',
   '__file__',
   '__name__',
   '__package__',
   '__path__']
Run Code Online (Sandbox Code Playgroud)

似乎fromlist按照我们的预期工作.但是当我们尝试在a上做同样的事情时,事情变得有线module.假设我们有一个名为C.py的模块和代码:

  handlers = {}

  def hello():
      print "hello"

  test_list = []
Run Code Online (Sandbox Code Playgroud)

所以现在我们尝试对它做同样的事情.

  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']
Run Code Online (Sandbox Code Playgroud)

所以,当我们只想导入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']
Run Code Online (Sandbox Code Playgroud)

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