导入工具 VS 从工具导入安全
import werkzeug VS from werkzeug import security
我目前对 Python 中的导入如何工作的理解(基于这些答案:one, two, ; and Python documentation)是 (以防万一:所有代码片段都经过测试Python 3.6.1):
假设我们有一个模块 mod
,它有子模块 sub
和 sub1
; sub
,反过来,有一个函数func
;那么我们可以(当然,假设 mod
安装在当前环境中):
import mod
mod.sub.func()
mod.sub1
# or
import mod.sub
mod.sub.func()
mod.sub1 # will result in "NameError: name 'mod' is not defined"
# or
from mod.sub import func
func()
mod.sub.func() # will result in "NameError: name 'mod' is not defined"
mod.sub1 # will result in "NameError: name 'mod' is not defined"
最近,在玩 werkzeug.security.generate_password_hash
和 werkzeug.security.check_password_hash
时,在 Python 控制台中,我注意到:
import werkzeug
werkzeug.security.generate_password_hash('some_password', method='pbkdf2:sha512', salt_length=25)
结果 AttributeError: module 'werkzeug' has no attribute 'security'
。
尽管如此,以下工作正常:
from werkzeug import security
security.generate_password_hash('some_password', method='pbkdf2:sha512', salt_length=25)
这个(当然)也是:
import werkzeug.security
werkzeug.security.generate_password_hash('some_password', method='pbkdf2:sha512', salt_length=25)
还有这个:
from werkzeug.security import generate_password_hash
generate_password_hash('some_password', method='pbkdf2:sha512', salt_length=25)
而且,有点令人惊讶(至少对我而言),这个:
import werkzeug
from werkzeug import security
werkzeug.security.generate_password_hash('some_password', method='pbkdf2:sha512', salt_length=25)
我的问题是:
- 关于
import
如何在 Python 中工作,我的一些想法是否错误(或缺乏细节)?
- 为什么
import werkzeug
不允许我访问 werkzeug.security
?我的理解是 — 它应该导入 werkzeug
,连同所有 submodules/attributes.
- 为什么
import werkzeug
+ from werkzeug import security
允许访问 werkzeug.security
?我的理解:它应该绑定两个单独的名称(它们之间没有连接),如下:werkzeug
到import werkzeug
(即werkzeug
模块) security
到 from werkzeug import security
(即 werkzeug
模块的 security
子模块。
我不确定我是否能够很好地回答你的所有问题,但我发现它很有趣并看了一下,这是我的结果。
通常,import mod.sub
或 from mod import sub
假定 sub
是 mod
包中的子模块。但是,这也可能意味着 sub
是在 mod
模块中声明的 field/variable。
存在__init.py__-文件will denote一个文件夹是一个包:
The __init__.py files are required to make Python treat the directories as containing packages; this is done to prevent directories with a common name, such as string, from unintentionally hiding valid modules that occur later on the module search path. In the simplest case, __init__.py can just be an empty file, but it can also execute initialization code for the package (...).
我相信,from werkzeug import security
和 import werkzeug.security
都导入了一个模块 security
,因此 security.generate_password_hash
是一个已知且有效的属性。基本上,from werkzeug.security import generate_password_hash
通过有效的导入语句直接导入那个属性。
在 Werkzeug Quickstart 文档中,我发现了以下内容:
Make sure to import all objects from the places the documentation suggests. It is theoretically possible in some situations to import objects from different locations but this is not supported.
此外,Werkzeug transition to 1.0 指出:
Werkzeug originally had a magical import system hook that enabled everything to be imported from one module and still loading the actual implementations lazily as necessary. Unfortunately this turned out to be slow and also unreliable on alternative Python implementations and Google’s App Engine.
Starting with 0.7 we recommend against the short imports and strongly encourage starting importing from the actual implementation module. Werkzeug 1.0 will disable the magical import hook completely.
看来 Werkzeug modifies 模块是如何加载的。 (我推测这在具有 contrib-content 的大包中并不少见,例如 Flask、Django;受延迟加载、提高性能或管理分布在包中的贡献模块内容的能力的推动。)
如您所见,import werkzeug
不会 从 werkzeug
模块导入 security
,因为(据我了解),将作为属性导入的 仅 子模块是在 __init__.py:
的 line 100 上定义的子模块
# modules that should be imported when accessed as attributes of werkzeug
attribute_modules = frozenset(['exceptions', 'routing'])
在同一文件中,当 looking at Werkzeug 的 module(ModuleType)
-class 及其 __getattr__()
-方法时:
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
是one of them。
最后,我认为原因是:
import werkzeug
from werkzeug import security
组合有效,第一行 不 导入安全,但第二行 执行 ,并且 __getattr__()
-方法将 return 显式导入的模块。
编辑: 最后一节不正确,由 Filipp 测试:
我希望只做 from werkzeug import security
仍然 werkzeug.security.generate_password_hash()
可以工作。 (我没有测试或证实这一点)
TL;DR:直接从werkzeug
导入all_by_module
dictionary中包含的任何属性,即from werkzeug import generate_password_hash
.
受到/基于的启发,我会尝试总结一下我自己的问题的答案:
- Am I wrong (or lacking details) in some of my notions, concerning how
import
works in Python?
从我目前的立场来看,简短的回答是否定的。不过,最好记住 import rules/mechanics 可以通过 __init__.py
在包级别自定义。
关于主题的进一步阅读:Python import system, official docs on importlib
, Importing Python Modules 文章。
- Why
import werkzeug
won't give me access to werkzeug.security
? My understanding is — it should import werkzeug
, along with all of it's submodules/attributes.
As Thomas Fauskanger, correctly pointed out in his : import werkzeug
does not import security
from the werkzeug
module, because the only submodules that will be imported as attributes — are those defined on line 100 of the Werkzeug's __init__.py
(即 exceptions
和 routing
)。这个假设可以通过以下方式验证:
import werkzeug
werkzeug.routing # will return path to routing.py module
werkzeug.exceptions # will return path to exceptions.py module
werkzeug.security # AttributeError: module 'werkzeug' has no attribute 'security'
- Why
import werkzeug
+ from werkzeug import security
allows access to werkzeug.security
? My understanding: it should bind two separate names (with no connections between them), as follows: werkzeug
to import werkzeug
(i.e. werkzeug
module) and security
to from werkzeug import security
(i.e. security
submodule of werkzeug
module.
这是一个棘手的问题。正如 Werkzeug 的 __init__.py
中所示,docstring for module's __dir__
function:
Just show what we want to show.
这(可能)是原因:
import werkzeug
dir1 = dir(werkzeug)
werkzeug.security # AttributeError: module 'werkzeug' has no attribute 'security'
from werkzeug import security
dir2 = dir(werkzeug)
werkzeug.security # will return path to security.py module
# BUT!
dir1 == dir2 # True
我想,Thomas 也在这里,并且:
...__getattr__()
method will return modules that are explicitly imported.
结论(或者我的学习=):
如 docstring for Werkzeug's __init__.py
中所述:
...
The majority of the functions and classes provided by Werkzeug work on the HTTP and WSGI layer. There is no useful grouping for those which is why they are all importable from "werkzeug" instead of the modules where they are implemented.
...
The implementation of a lazy-loading module in this file replaces the werkzeug package when imported from within. Attribute access to the werkzeug module will then lazily import from the modules that implement the objects.
这意味着,而不是:
from werkzeug import security
security.generate_password_hash('some_password', method='pbkdf2:sha512', salt_length=25)
# OR
import werkzeug.security
werkzeug.security.generate_password_hash('some_password', method='pbkdf2:sha512', salt_length=25)
# OR
from werkzeug.security import generate_password_hash
generate_password_hash('some_password', method='pbkdf2:sha512', salt_length=25)
# OR
import werkzeug
from werkzeug import security
werkzeug.security.generate_password_hash('some_password', method='pbkdf2:sha512', salt_length=25)
你可以简单地做:
from werkzeug import generate_password_hash
generate_password_hash('some_password', method='pbkdf2:sha512', salt_length=25)
您可以以相同的方式导入和使用 all_by_module
dictionary 中包含的任何属性。
如果您遵循此语法,它将工作正常。
import werkzeug as xyz
有了它,您还可以执行 xyz.generate_hash_password()
或调用 xyz
的任何其他功能。
我目前对 Python 中的导入如何工作的理解(基于这些答案:one, two,
假设我们有一个模块 mod
,它有子模块 sub
和 sub1
; sub
,反过来,有一个函数func
;那么我们可以(当然,假设 mod
安装在当前环境中):
import mod
mod.sub.func()
mod.sub1
# or
import mod.sub
mod.sub.func()
mod.sub1 # will result in "NameError: name 'mod' is not defined"
# or
from mod.sub import func
func()
mod.sub.func() # will result in "NameError: name 'mod' is not defined"
mod.sub1 # will result in "NameError: name 'mod' is not defined"
最近,在玩 werkzeug.security.generate_password_hash
和 werkzeug.security.check_password_hash
时,在 Python 控制台中,我注意到:
import werkzeug
werkzeug.security.generate_password_hash('some_password', method='pbkdf2:sha512', salt_length=25)
结果 AttributeError: module 'werkzeug' has no attribute 'security'
。
尽管如此,以下工作正常:
from werkzeug import security
security.generate_password_hash('some_password', method='pbkdf2:sha512', salt_length=25)
这个(当然)也是:
import werkzeug.security
werkzeug.security.generate_password_hash('some_password', method='pbkdf2:sha512', salt_length=25)
还有这个:
from werkzeug.security import generate_password_hash
generate_password_hash('some_password', method='pbkdf2:sha512', salt_length=25)
而且,有点令人惊讶(至少对我而言),这个:
import werkzeug
from werkzeug import security
werkzeug.security.generate_password_hash('some_password', method='pbkdf2:sha512', salt_length=25)
我的问题是:
- 关于
import
如何在 Python 中工作,我的一些想法是否错误(或缺乏细节)? - 为什么
import werkzeug
不允许我访问werkzeug.security
?我的理解是 — 它应该导入werkzeug
,连同所有 submodules/attributes. - 为什么
import werkzeug
+from werkzeug import security
允许访问werkzeug.security
?我的理解:它应该绑定两个单独的名称(它们之间没有连接),如下:werkzeug
到import werkzeug
(即werkzeug
模块)security
到from werkzeug import security
(即werkzeug
模块的security
子模块。
我不确定我是否能够很好地回答你的所有问题,但我发现它很有趣并看了一下,这是我的结果。
通常,import mod.sub
或 from mod import sub
假定 sub
是 mod
包中的子模块。但是,这也可能意味着 sub
是在 mod
模块中声明的 field/variable。
存在__init.py__-文件will denote一个文件夹是一个包:
The __init__.py files are required to make Python treat the directories as containing packages; this is done to prevent directories with a common name, such as string, from unintentionally hiding valid modules that occur later on the module search path. In the simplest case, __init__.py can just be an empty file, but it can also execute initialization code for the package (...).
我相信,from werkzeug import security
和 import werkzeug.security
都导入了一个模块 security
,因此 security.generate_password_hash
是一个已知且有效的属性。基本上,from werkzeug.security import generate_password_hash
通过有效的导入语句直接导入那个属性。
在 Werkzeug Quickstart 文档中,我发现了以下内容:
Make sure to import all objects from the places the documentation suggests. It is theoretically possible in some situations to import objects from different locations but this is not supported.
此外,Werkzeug transition to 1.0 指出:
Werkzeug originally had a magical import system hook that enabled everything to be imported from one module and still loading the actual implementations lazily as necessary. Unfortunately this turned out to be slow and also unreliable on alternative Python implementations and Google’s App Engine.
Starting with 0.7 we recommend against the short imports and strongly encourage starting importing from the actual implementation module. Werkzeug 1.0 will disable the magical import hook completely.
看来 Werkzeug modifies 模块是如何加载的。 (我推测这在具有 contrib-content 的大包中并不少见,例如 Flask、Django;受延迟加载、提高性能或管理分布在包中的贡献模块内容的能力的推动。)
如您所见,import werkzeug
不会 从 werkzeug
模块导入 security
,因为(据我了解),将作为属性导入的 仅 子模块是在 __init__.py:
# modules that should be imported when accessed as attributes of werkzeug
attribute_modules = frozenset(['exceptions', 'routing'])
在同一文件中,当 looking at Werkzeug 的 module(ModuleType)
-class 及其 __getattr__()
-方法时:
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
是one of them。
最后,我认为原因是:
import werkzeug
from werkzeug import security
组合有效,第一行 不 导入安全,但第二行 执行 ,并且 __getattr__()
-方法将 return 显式导入的模块。
编辑: 最后一节不正确,由 Filipp 测试:
我希望只做 from werkzeug import security
仍然 werkzeug.security.generate_password_hash()
可以工作。 (我没有测试或证实这一点)
TL;DR:直接从werkzeug
导入all_by_module
dictionary中包含的任何属性,即from werkzeug import generate_password_hash
.
受到/基于
- Am I wrong (or lacking details) in some of my notions, concerning how
import
works in Python?
从我目前的立场来看,简短的回答是否定的。不过,最好记住 import rules/mechanics 可以通过 __init__.py
在包级别自定义。
关于主题的进一步阅读:Python import system, official docs on importlib
, Importing Python Modules 文章。
- Why
import werkzeug
won't give me access towerkzeug.security
? My understanding is — it should importwerkzeug
, along with all of it's submodules/attributes.
As Thomas Fauskanger, correctly pointed out in his import werkzeug
does not import security
from the werkzeug
module, because the only submodules that will be imported as attributes — are those defined on line 100 of the Werkzeug's __init__.py
(即 exceptions
和 routing
)。这个假设可以通过以下方式验证:
import werkzeug
werkzeug.routing # will return path to routing.py module
werkzeug.exceptions # will return path to exceptions.py module
werkzeug.security # AttributeError: module 'werkzeug' has no attribute 'security'
- Why
import werkzeug
+from werkzeug import security
allows access towerkzeug.security
? My understanding: it should bind two separate names (with no connections between them), as follows:werkzeug
toimport werkzeug
(i.e.werkzeug
module) andsecurity
tofrom werkzeug import security
(i.e.security
submodule ofwerkzeug
module.
这是一个棘手的问题。正如 Werkzeug 的 __init__.py
中所示,docstring for module's __dir__
function:
Just show what we want to show.
这(可能)是原因:
import werkzeug
dir1 = dir(werkzeug)
werkzeug.security # AttributeError: module 'werkzeug' has no attribute 'security'
from werkzeug import security
dir2 = dir(werkzeug)
werkzeug.security # will return path to security.py module
# BUT!
dir1 == dir2 # True
我想,Thomas 也在这里,并且:
...
__getattr__()
method will return modules that are explicitly imported.
结论(或者我的学习=):
如 docstring for Werkzeug's __init__.py
中所述:
...
The majority of the functions and classes provided by Werkzeug work on the HTTP and WSGI layer. There is no useful grouping for those which is why they are all importable from "werkzeug" instead of the modules where they are implemented.
...
The implementation of a lazy-loading module in this file replaces the werkzeug package when imported from within. Attribute access to the werkzeug module will then lazily import from the modules that implement the objects.
这意味着,而不是:
from werkzeug import security
security.generate_password_hash('some_password', method='pbkdf2:sha512', salt_length=25)
# OR
import werkzeug.security
werkzeug.security.generate_password_hash('some_password', method='pbkdf2:sha512', salt_length=25)
# OR
from werkzeug.security import generate_password_hash
generate_password_hash('some_password', method='pbkdf2:sha512', salt_length=25)
# OR
import werkzeug
from werkzeug import security
werkzeug.security.generate_password_hash('some_password', method='pbkdf2:sha512', salt_length=25)
你可以简单地做:
from werkzeug import generate_password_hash
generate_password_hash('some_password', method='pbkdf2:sha512', salt_length=25)
您可以以相同的方式导入和使用 all_by_module
dictionary 中包含的任何属性。
如果您遵循此语法,它将工作正常。
import werkzeug as xyz
有了它,您还可以执行 xyz.generate_hash_password()
或调用 xyz
的任何其他功能。