首页 > 解决方案 > 为什么 from ... import ... 语句包含隐式导入?

问题描述

给定一个包:

package/
├── __init__.py
└── module.py

__init__.py:

from .module import function

模块.py:

def function():
    pass

可以导入包并打印其名称空间。

python -c 'import package; print(dir(package))'
['__builtins__', ..., 'function', 'module']

问题:

为什么仅在导入时package包含命名空间?modulefunction__init__.py

我原以为package' 的命名空间将只包含function而不包含module. 文档中也提到了这种机制,

“当使用任何机制(例如 importlib API、import 或 import-from 语句或内置__import__())加载子模块时,将在父模块的命名空间中放置与子模块对象的绑定。”

但并没有真正的动力。对我来说,这个选择似乎很奇怪,因为我认为子模块是结构包的实现细节,并且不期望它们成为 API 的一部分,因为结构可以改变。

我也知道“Python 是为成年人所用的”,并且不能真正对用户隐藏任何东西。但我会争辩说,将子模块名称绑定到包的范围会使用户不太清楚什么是 API 的实际部分以及可以更改的内容。

为什么不使用一个__sub_modules__属性来让用户可以访问子模块?这个设计决定的原因是什么?

标签: pythonpython-3.xpython-importpython-packaging

解决方案


You say you think of submodules as implementation details. This is not the design intent behind submodules; they can be, and extremely commonly are, part of the public interface of a package. The import system was designed to facilitate access to submodules, not to prevent access.

Loading a submodule places a binding into the parent's namespace because this is necessary for access to the module. For example, after the following code:

import package.submodule

the expression package.submodule must evaluate to the module object for the submodule. package evaluates to the module object for the package, so this module object must have a submodule attribute referring to the module object for the submodule.

At this point, you are almost certainly thinking, "hey, there's no reason from .submodule import function has to do the same thing!" It does the same thing because this attribute binding is part of submodule initialization, which only happens on the first import, and which needs to do the same setup regardless of what kind of import triggered it.

This is not an extremely strong reason. With enough changes and rejiggering, the import system definitely could have been designed the way you expect. It was not designed that way because the designers had different priorities than you. Python's design cares very little about hiding things or supporting any notion of privacy.


推荐阅读