python - 在 Python 包的 __init__.py 文件中,有没有办法检测包是否直接执行?
问题描述
我想要一种方法来检测我的模块是否是直接执行的,例如 inimport module
或from module import *
而不是 by import module.submodule
(它也执行module
),并且可以在module
's中访问这些信息__init__.py
。
这是一个用例:
在 Python 中,一个常见的习惯用法是在模块__init__.py
文件中添加 import 语句,例如“扁平化”模块的命名空间并使其子模块可以直接访问。不幸的是,这样做会使加载特定子模块非常慢,因为导入的所有其他同级__init__.py
也会执行。
例如:
module/
__init__.py
submodule/
__init__.py
...
sibling/
__init__.py
...
通过添加到module/__init__.py
:
from .submodule import *
from .sibling import *
现在,模块的用户可以在不知道包结构细节的情况下访问子模块中的定义(即from module import SomeClass
SomeClass 在某处定义submodule
并在其自己的__init__.py
文件中公开)。
但是,如果我现在submodule
直接运行(如import module.submodule
通过调用python3 -m module.submodule
,甚至通过 pytest 间接运行),我也将不可避免地执行sibling
!如果兄弟姐妹很大,这可能会无缘无故减慢速度。
相反,我想写module/__init__.py
一些类似的东西:
if __???__ == 'module':
from .submodule import *
from .sibling import *
Where__???__
给了我导入的完全限定名称。任何类似的机制也可以工作,尽管我最感兴趣的是一般情况(检测直接执行)而不是这个具体的例子。
解决方案
module
当我们考虑导入系统实际上是如何工作的(如果它实际上是可能的)时,所期望的是会导致未定义的行为(从某种意义上说,扁平化的名称是否可以从 导入)。
假设地,如果您想要实现的目标是可能的,那么其中一些__dunder__
会消除用于导入的 import 语句的歧义module/__init__.py
(例如import module
and from module import *
、 vs import module.submodule
。对于第一种情况,module
可能会触发后续(慢)导入以产生“扁平化”版本所需的导入,而后一种情况 ( import module.submodule
) 将避免这种情况,因此module
不会包含任何“扁平化”导入的分配。
为了进一步说明该示例,假设可以通过简单地执行文件执行语句来创建该绑定来导入SiblingClass
from 。但是,如果执行导致避免了 flatten 导入,我们会得到以下场景:module.sibling.SiblingClass
from module import SiblingClass
module/__init__.py
from .sibling import *
import module.submodule
import module.submodule
# module.submodule gets imported
from module import SiblingClass
# ImportError will occur
这是为什么?这仅仅是由于 Python 导入文件的方式——源文件被完整执行一次,以将导入、函数和类声明分配给指定的名称,并sys.modules
在其导入名称下注册。再次导入模块将不会再次执行该文件,因此如果该from .sibling import *
语句在其初始导入期间未执行(即import module.submodule
),则在后续导入同一模块期间将永远不会再次执行,因为初始导入生成的副本分配给返回其模块条目sys.module
(除非手动重新加载模块,否则将再次执行该模块的代码)。
您可以通过将语句放入文件中来验证这一事实print
,导入相应的模块以查看产生的输出,并看到该模块的后续导入不会产生进一步的输出(相关:当一个模块被导入两次时会发生什么? )。
实际上,问题中描述的所需功能无法在 Python 中实现。
关于这个主题的一个相关线程:How to import sub module without exec __init__.py in package
推荐阅读
- postgresql - How to sort Alphanumeric using Postgresql (specific data)?
- python - 我怎样才能让这两个脚本一起工作?
- c++ - 检查类是否可流式传输的概念
- php - Laravel 6 上的 MySQL (errno: 150 "外键约束格式不正确")")
- python - 获取上个月的第一天 - 月份必须在 1..12
- javascript - ReactJS:当另一个组件中的状态属性值为某个值时,如何更改组件中的状态属性值
- mysql - LOAD DATA LOCAL INFILE 无法正常工作
- asp.net - .net 会员资格的升级路径
- javascript - 在包 ngx-owl-carousel-o 中以角度触发猫头鹰轮播的刷新
- javascript - Puppeteer 如何将结果存储在对象变量中?