包裹 'see' 本身在 __init__.py 中吗?

Does a package 'see' itself in __init__.py?

我有一个 flask 应用程序,其根文件夹名为 project_folder

project_folder 包的 __init__.py 文件中的代码片段:

@jwt.token_in_blacklist_loader
def check_if_token_in_blacklist(decrypted_token):
    jti = decrypted_token['jti']
    return project_folder.Model.RevokedTokenModel.is_jti_blacklisted(jti)

from project_folder.Controller.root import root
from project_folder.Controller import auth_controller
from project_folder.Controller import item_controller

现在有趣的是,project_folder 包本身自然有其他较小的包,我正在导入这些包以使用它们(在本例中用于 REST 资源)。这些是最后 3 行,到目前为止没有任何错误。

但是,如果您看一下带注释的函数(在此示例中,它总是在使用某种 JWT 令牌之前运行),我将返回一些内部包的函数。现在,当逻辑真正运行这部分时,代码中断:

PROJECT_ROUTE\project_folder\__init__.py", line 38, in check_if_token_in_blacklist
    return project_folder.Model.RevokedTokenModel.is_jti_blacklisted(jti)
NameError: name 'project_folder' is not defined

想了想,好像可以理解。从 project_folder 导入确实是从包的 __init__.py 文件导入,这是解释器当前所在的实际文件。所以从

中删除包名称前缀
return project_folder.Model.RevokedTokenModel.is_jti_blacklisted(jti)

return Model.RevokedTokenModel.is_jti_blacklisted(jti)

不再抛出错误。

问题是:为什么它只是回调函数内部的问题而不是最后 3 个导入的问题?

这与 python 中的循环导入有关。循环导入是循环依赖的一种形式,在模块导入级别创建。

工作原理:

当您启动您的应用程序时,python 会保留一个寄存器(一种 table),其中记录了所有导入的模块。当您在代码中的某处调用模块时,python 将在其注册表中查看它是否已经注册并从那里加载它。您可以通过 sys.module 访问此注册表,它实际上是一个 dictionary,其中包含自 Python 启动以来已导入的所有模块。

使用示例:

>>> import sys
>>> print('\n'.join(sys.modules.keys()))

所以,由于Python是一种解释型语言,代码的读取和执行是从上到下逐行完成的。

在您的代码中,您将导入放在 __init__.py 文件的底部。

浏览时,当python到达第return project_folder.Model.RevokedTokenModel.is_jti_blacklisted(jti)行时,它会查看该模块是否存在于它的寄存器中。显然情况还不是这样。这就是他提出 NameError: name 'project_folder' is not defined 异常的原因。