我有一个脚本,可以加载各种模块来完成其工作.其中一些模块充斥着assert语句-足以潜在地导致实际使用中的显着降低. (我正在做很多涉及变异图的操作,因此有很多断言可以遍历整个图以强制执行不变式或检查结果的正确性.)因此,我想允许用户在以下情况下禁用这些检查:他们希望.看起来很简单;这正是-O标志的功能,对吧?
但是,问题是-O是Python解释器处理的标志.我不想强迫我的用户仅为了访问此功能而显式调用解释器-我想支持MyScript.py -O,而不是python -O MyScript.py.有什么办法可以做到吗?
我知道__debug__不能在运行时设置;它在语言中是特殊的,是不变的常量.但是,主脚本中没有任何有问题的assert语句,并且我可以轻松地将其他模块的加载延迟到完成对命令行参数的解析之后.因此,如果有某种方法可以从Python内部设置-O标志,或者有某种带有标志的导入功能,则可以做到这一点.
注1:需要明确的是,仅禁用assert语句还不够.还有一些代码以__debug__常量为条件(例如if(__debug__):对于large_expensive_set中的x:断言some_property_of(x)),该代码无需执行.
注意2:另一方面,我不关心代码的内存大小,仅关心速度,而我的速度关注是基于assert语句中昂贵的函数和debug-only代码中昂贵的循环的.我知道Python的代码生成器在-O模式下运行时会省略assert语句,并且如果(__debug__):已编译代码中的代码块,但是如果不发生这种情况也很好-我不在乎是否只调试语句存在,只要它们不执行.
注意3:我已经考虑过绕过一个手动调试标志,并用if(self .__ debug而不是assert_condition)替换所有assert:raise AssertionError().但是,该解决方案:
>可读性极差
>效率低得多
>需要更改大量代码
>需要非平凡的重构(每个对象都必须带有调试标志,将其存储,然后传递给它产生的每个子对象)
解决方法:
如果设置了__debug__,则可以重新启动自己.在脚本顶部,尝试以下操作:
if __debug__:
import os
import sys
os.execv(sys.executable, ['python', '-O'] + sys.argv)
这将使用python -O将运行的进程替换为新进程.请注意,os.execv永远不会返回-它确实会替换正在运行的进程.
这种方法的一个怪癖是它不会保留Python解释器的选项,因此,如果运行python -m cProfile myscript,它将在没有cProfile的情况下重新启动.我不确定如何解决此问题… sys.flags
会告诉您设置了哪些布尔选项,但不会告诉您-m参数.我认为这本身很有趣,因此在此处创建了一个单独的问题:Retrieve the command line arguments of the Python interpreter