How to know if python script was run using interpreter's -m option?
阅读完所有内容后,我找不到答案:
-
PEP 338将模块作为脚本执行
-
runpy标准模块的文档
-
Python解释器的-m选项的描述
理由:
当在没有-m选项的情况下运行使用相对导入的测试脚本时,我可以打印警告消息,而不是让用户使用标准回溯导致ValueError: Attempted relative import in non-package异常。 在不知道这一点的情况下,我可以捕获此异常并且仅表明缺少-m选项可能是错误的原因。
-
你需要什么? 你能举一些例子或一个测试用例,这个需求变得明显吗?
免责声明:这只是一个观察,我没有在文档中看到它,因此它可能是依赖于实现的,并且可能在不同的Python版本中不一致。
我注意到当使用-m选项调用脚本时,名为__loader__的变量被添加到命名空间中,因此在脚本的顶部可以检查该变量是否存在:
1 2
| if '__loader__' in globals():
# called with -m |
为了一些额外的安全性,您可以检查__loader__是否是pkgutil.ImpLoader的实例:
1
| if '__loader__' in globals() and __loader__.__class__.__name__ == 'ImpLoader': |
-
这是runpy模块的文档;在执行模块代码之前,在全局字典中设置特殊全局变量__name__,__file__,__loader__和__package__(请注意,这是一组最小变量 - 其他变量可以隐式设置为口译员实施细节)。然而,__loader__是一种通用的,我们永远不知道有一天可能会设置它...
-
+1这是一个非常合理的解决方案。
-
@RaymondHettinger有没有理由在这种情况下没有真正独特的全局变量集?
-
唯一保证的唯一变量是None和__debug __;但是,任何双重强制名称都被视为由核心开发人员保留以供创建,因此__loader__在某种程度上是安全的(或者至少与__name__=='__main__'一样安全)。如果它让你夜不能寐,那么总是可以反省物体以验证匹配。
-
我很好奇你为什么不使用isinstance?
-
@PiotrDobrogost - pkgutil.ImpLoader不是命名空间的一部分,需要先导入它。这是另一种选择。
另一个观察是,当使用-m时,__package__设置为None,当使用-m时,设置为包名称(当模块未包含在任何包中时使用空字符串,因此它仍然不同于None)。
-
太好了!这不仅是观察,因为这是PEP 366主要模块明确相对进口的强制要求。