为什么导入Python模块时不会导入嵌套的模块?

14

如果我这样做:

import lxml 

在Python中,lxml.html没有被导入。例如,我无法调用lxml.html.parse()函数。为什么会这样?


3
你可能已经注意到,import os 允许你在代码中使用 os.path.whatever。所以这取决于模块的作者。 - Greg Hewgill
5个回答

15

在Python中导入模块或包是一个概念上很简单的操作:

  1. 查找与导入对应的.py文件。这涉及到Python路径和一些其他机制,但最终会找到一个特定的.py文件。

  2. 对于每个导入的目录级别(例如import foo.bar.baz有两个级别),找到相应的__init__.py文件并执行它。执行它就是运行文件中所有顶层语句。

  3. 最后,执行.py文件本身(在这种情况下为foo/bar/baz.py),这意味着执行所有顶层语句。由该执行创建的所有全局变量都打包到一个模块对象中,并且该模块对象是导入的结果。

如果没有任何步骤导入子包,则这些子包不可用。如果导入了子包,则它们是可用的。包作者可以按照自己的意愿进行设置。


1
我认为值得澄清的是,在导入包时,步骤1中找到的.py文件是该包的__init__.py。除非在该__init__.py文件中导入子包,否则它们将不可用。 - C S
“from foo.bar import baz” 不是豁免此规则吗?就我个人的项目而言,即使所有的 __init__.py 文件都为空,这样的导入也能正常工作。请同时查看我发布的问题:https://stackoverflow.com/questions/57772706/importing-deeply-nested-modules-in-python - z33k

6
是Python中的一个,它是由多个模块组成的层次集合。由于包可能很大,因此在导入时允许选择性地拉取内容。否则每个人都必须导入整个层次结构,这将是一种资源浪费。


4

这是有意为之的。该包在其__init__.py中有导入嵌套包的选项,因此您可以轻松访问嵌套包。这是包作者的选择问题,目的是最小化您可能不会使用的代码量。


2

lxml 是一个包,而不是一个模块。包是模块的集合。恰好地,你也可以直接导入该包,但这并不会自动导入其所有子模块。

至于为什么,那就是BDFL的问题了。我认为这可能是因为包通常相当大,导入所有子模块将会产生过大的性能损失。


1

这是为了只加载最少量的代码,以便于使用多部分库时不必全部加载。例如,您可能不会使用 lxmlhtml 部分,因此不想处理加载其代码的问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接