从werkzeug导入安全导入werkzeug VS.

时间:2017-12-07 06:31:37

标签: python python-3.x python-import python-3.6 werkzeug

我目前对Python中导入方式的理解(基于这些答案:onetwothree;以及Python documentation(仅限于重要的是:所有代码片段都在Python 3.6.1上进行了测试

假设我们有一个模块mod,其中包含子模块subsub1;反过来,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_hashwerkzeug.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)

我的问题是:

  1. 我的一些观念中是否错误(或缺乏细节),关于import如何在Python中运行?
  2. 为什么import werkzeug不允许我访问werkzeug.security?我的理解是 - 它应该导入werkzeug及其所有子模块/属性。
  3. 为什么import werkzeug + from werkzeug import security允许访问werkzeug.security?我的理解:它应该绑定两个单独的名称(它们之间没有连接),如下所示:werkzeugimport werkzeug(即werkzeug模块)和{{ 1}}到security(即from werkzeug import security模块的security子模块。

3 个答案:

答案 0 :(得分:1)

我不确定我能否对你的所有问题给出一个好的答案,但我发现它很有趣并看了一下,这是我的结果。

通常,import mod.subfrom mod import sub假定submod包中的子模块。但是,它也可能意味着submod模块中声明的字段/变量。

文件夹是包的 __ init.py __ -file will denote的存在:

  

需要__init__.py文件才能使Python将目录视为包含包;这样做是为了防止具有通用名称的目录(例如字符串)无意中隐藏稍后在模块搜索路径上发生的有效模块。在最简单的情况下,__ init__.py可以只是一个空文件,但它也可以执行包的初始化代码(...)。

我相信,from werkzeug import securityimport 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.securityone 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的启发,我将尝试总结自己问题的答案:

  
      
  1. 我的一些观念中是否错误(或缺乏细节),关于import如何在Python中运行?
  2.   

从我目前的立场来看,简短的回答是否定的。但是,记住导入规则/机制可以通过__init__.py在包级别进行自定义,这很好。
进一步阅读主题:Python import system,官方docs on importlibImporting Python Modules文章。

  
      
  1. 为什么import werkzeug无法让我访问werkzeug.security?我的理解是 - 它应该导入werkzeug及其所有子模块/属性。
  2.   

作为Thomas Fauskanger,在answer中正确指出:import werkzeug不会从security模块导入werkzeug,因为唯一的子模块将是导入为属性 - 是line 100 of the Werkzeug's __init__.py上定义的属性(exceptionsrouting)。这个假设可以通过以下方式验证:

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'
  
      
  1. 为什么import werkzeug + from werkzeug import security允许访问werkzeug.security?我的理解:它应该绑定两个单独的名称(它们之间没有连接),如下所示:werkzeugimport werkzeug(即werkzeug模块)和{{ 1}}到security(即from werkzeug import security模块的security子模块。
  2.   

这是一个棘手的问题。正如Werkzeug的werkzeugdocstring 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 的任何其他功能。