我目前对Python中导入方式的理解(基于这些答案:one,two,three;以及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
及其所有子模块/属性。import werkzeug
+ from werkzeug import security
允许访问werkzeug.security
?我的理解:它应该绑定两个单独的名称(它们之间没有连接),如下所示:werkzeug
到import werkzeug
(即werkzeug
模块)和{{ 1}}到security
(即from werkzeug import security
模块的security
子模块。答案 0 :(得分:1)
我不确定我能否对你的所有问题给出一个好的答案,但我发现它很有趣并看了一下,这是我的结果。
通常,import mod.sub
或from mod import sub
假定sub
是mod
包中的子模块。但是,它也可能意味着sub
是mod
模块中声明的字段/变量。
文件夹是包的 __ init.py __ -file will denote的存在:
需要__init__.py文件才能使Python将目录视为包含包;这样做是为了防止具有通用名称的目录(例如字符串)无意中隐藏稍后在模块搜索路径上发生的有效模块。在最简单的情况下,__ init__.py可以只是一个空文件,但它也可以执行包的初始化代码(...)。
我相信,from werkzeug import security
和import werkzeug.security
都会导入模块security
,因此security.generate_password_hash
是一个已知且有效的属性。基本上,from werkzeug.security import generate_password_hash
通过有效的import语句直接导入属性。
在Werkzeug Quickstart文档中,我发现了以下内容:
确保从文档建议的位置导入所有对象。理论上,在某些情况下可以从不同位置导入对象,但这不受支持。
此外,Werkzeug transition to 1.0声明:
Werkzeug最初有一个神奇的导入系统挂钩,可以从一个模块导入所有内容,并在必要时仍懒得加载实际的实现。不幸的是,对于其他Python实现和Google的App Engine,这种情况变得缓慢且不可靠。
从0.7开始,我们建议不要使用短进口,并强烈建议从实际的实施模块开始导入。 Werkzeug 1.0将完全禁用神奇的导入钩子。
似乎Werkzeug modifies如何加载模块。 (我推测这在包含contrib-content的大包中并不罕见,例如Flask,Django;由于能够延迟加载,提高性能或管理跨包传播的贡献模块内容而激发。)
正如您所发现的那样,import werkzeug
不会从security
模块导入werkzeug
,因为(据我所知),仅将作为属性导入的子模块是在__init __的line 100上定义的子模块.py:
# modules that should be imported when accessed as attributes of werkzeug
attribute_modules = frozenset(['exceptions', 'routing'])
在同一个文件中,当looking at Werkzeug的module(ModuleType)
- 类及其__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__()
- 方法将返回模块明确导入。
修改: 此最后一部分不正确,经Filipp 测试:
我希望只做 from werkzeug import security
仍然可以werkzeug.security.generate_password_hash()
起作用。 (我没有测试或证实这一点)
答案 1 :(得分:1)
TL; DR :直接从werkzeug
导入all_by_module
dictionary中包含的任何属性,即from werkzeug import generate_password_hash
。
受Thomas's answer的启发,我将尝试总结自己问题的答案:
- 我的一些观念中是否错误(或缺乏细节),关于
醇>import
如何在Python中运行?
从我目前的立场来看,简短的回答是否定的。但是,记住导入规则/机制可以通过__init__.py
在包级别进行自定义,这很好。
进一步阅读主题:Python import system,官方docs on importlib
,Importing Python Modules文章。
- 为什么
醇>import werkzeug
无法让我访问werkzeug.security
?我的理解是 - 它应该导入werkzeug
及其所有子模块/属性。
作为Thomas Fauskanger,在answer中正确指出:import werkzeug
不会从security
模块导入werkzeug
,因为唯一的子模块将是导入为属性 - 是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'
- 为什么
醇>import werkzeug
+from werkzeug import security
允许访问werkzeug.security
?我的理解:它应该绑定两个单独的名称(它们之间没有连接),如下所示:werkzeug
到import werkzeug
(即werkzeug
模块)和{{ 1}}到security
(即from werkzeug import security
模块的security
子模块。
这是一个棘手的问题。正如Werkzeug的werkzeug
,docstring for module's __dir__
function所示:
只显示我们想要展示的内容。
那可能是为什么:
__init__.py
我想,Thomas就在这里,并且:
...
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
方法将返回明确导入的模块。
结论 (或我学到的东西=):
如docstring for Werkzeug's __init__.py
中所述:
...
Werkzeug提供的大多数函数和类都在HTTP和WSGI层上工作。没有有用的分组,这就是为什么它们都可以从" werkzeug"而不是实现它们的模块。
...
从内部导入时,此文件中的延迟加载模块的实现将替换werkzeug包。然后,从实现对象的模块中懒惰地导入对werkzeug模块的属性访问。
这意味着什么,而不是:
__getattr__()
您可以这样做:
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)
您可以导入&以相同的方式使用all_by_module
dictionary中包含的任何属性。
答案 2 :(得分:0)
如果遵循此语法,则可以正常工作。
proguard-rules.pro
使用此方法,您还可以执行net.sourceforge
或调用import werkzeug as xyz
的任何其他功能。