python - 为什么 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
包含命名空间?module
function
__init__.py
我原以为package
' 的命名空间将只包含function
而不包含module
. 文档中也提到了这种机制,
“当使用任何机制(例如 importlib API、import 或 import-from 语句或内置
__import__()
)加载子模块时,将在父模块的命名空间中放置与子模块对象的绑定。”
但并没有真正的动力。对我来说,这个选择似乎很奇怪,因为我认为子模块是结构包的实现细节,并且不期望它们成为 API 的一部分,因为结构可以改变。
我也知道“Python 是为成年人所用的”,并且不能真正对用户隐藏任何东西。但我会争辩说,将子模块名称绑定到包的范围会使用户不太清楚什么是 API 的实际部分以及可以更改的内容。
为什么不使用一个__sub_modules__
属性来让用户可以访问子模块?这个设计决定的原因是什么?
解决方案
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.
推荐阅读
- c - 如何处理 gdb 中的`__int128`?
- c# - 图像 iTextSharp 的坏边框
- c# - 在另一个列表中按值匹配对对象列表进行排序
- c# - 在鼠标悬停时突出显示相邻的六边形
- c# - 如何使用 C# 遍历 json 响应中具有相同名称的多个子节点并断言正确的内容
- kdb - 搜索具有 * 的字符串
- c# - 在列表视图中选择项目时出现字典和 KeyValuePair 错误
- swift - 发布获取 JSON 值 SWIFT Alamofire
- swift - Firebase 以两种不同的方式获取子数据
- ruby-on-rails - 如何在 swagger rails 中添加 msgpack 支持