我不确定我能否很好地回答您的所有问题,但我发现它很有趣并看了一下,这是我的结果。
一般来说,import mod.sub
or from mod import sub
假设sub
是一个子模块mod
包裹。然而,这也可能意味着sub
是在 a 中声明的字段/变量mod
module.
存在一个__init.py__-file 将表示 https://docs.python.org/3/tutorial/modules.html#packages文件夹是一个包:
需要 __init__.py 文件才能使 Python 将目录视为包含包;这样做是为了防止具有通用名称(例如字符串)的目录无意中隐藏稍后出现在模块搜索路径上的有效模块。在最简单的情况下,__init__.py 可以只是一个空文件,但它也可以执行包的初始化代码(...)。
我相信,from werkzeug import security
and import werkzeug.security
两者都导入一个模块security
, thus security.generate_password_hash
是已知且有效的属性。基本上,from werkzeug.security import generate_password_hash
通过有效的导入语句直接导入该属性。
In the Werkzeug 快速入门 http://werkzeug.pocoo.org/docs/0.13/quickstart/文档中,我发现了以下内容:
确保从文档建议的位置导入所有对象。理论上,在某些情况下可以从不同位置导入对象,但这不受支持。
此外,Werkzeug过渡到 1.0 http://werkzeug.pocoo.org/docs/0.13/transition/ states:
Werkzeug 最初有一个神奇的导入系统钩子,可以从一个模块导入所有内容,并且仍然根据需要延迟加载实际的实现。不幸的是,事实证明这很慢,而且在替代 Python 实现和 Google 的 App Engine 上也不可靠。
从 0.7 开始,我们建议不要进行短期导入,并强烈鼓励从实际实现模块开始导入。 Werkzeug 1.0 将完全禁用神奇的导入钩子。
看起来Werkzeug 修改 https://github.com/pallets/werkzeug/blob/master/werkzeug/__init__.py如何加载模块。 (我推测,这在具有贡献内容的大型包中并不罕见,例如 Flask、Django;其动机是延迟加载、提高性能或管理跨包传播的贡献模块内容。)
正如你所发现的,import werkzeug
does not import security
来自werkzeug
模块,因为(据我所知),only将作为属性导入的子模块是定义在line 100 https://github.com/pallets/werkzeug/blob/master/werkzeug/__init__.py#L100__init__.py 的:
# modules that should be imported when accessed as attributes of werkzeug
attribute_modules = frozenset(['exceptions', 'routing'])
在同一个文件中,当看着 https://github.com/pallets/werkzeug/blob/master/werkzeug/__init__.py#L110韦克泽格的module(ModuleType)
- 类及其__getattr__()
-method:
class module(ModuleType):
"""Automatically import objects from the modules."""
def __getattr__(self, name):
if name in object_origins:
module = __import__(object_origins[name], None, None, [name])
for extra_name in all_by_module[module.__name__]:
setattr(self, extra_name, getattr(module, extra_name))
return getattr(module, name)
elif name in attribute_modules:
__import__('werkzeug.' + name)
return ModuleType.__getattribute__(self, name)
看来模块名称在object_origins
字典,通过定义all_by_module
,必须单独导入,并且werkzeug.security
is 其中之一 https://github.com/pallets/werkzeug/blob/master/werkzeug/__init__.py#L95.
最后,我认为原因是:
import werkzeug
from werkzeug import security
组合有效,第一行就是这样not进口安全,但第二个does,和__getattr__()
-method 将返回显式导入的模块。
Edit: 最后一部分不正确,经过测试Filipp https://stackoverflow.com/users/8554766/filipp-w:
我希望通过简单地做from werkzeug import security
那仍然werkzeug.security.generate_password_hash()
会工作。 (我还没有测试或证实这一点)