我正在用 Python 编写需要尽可能高效运行的代码,但有时我需要深入挖掘调试语句。不要注释这些输入或输出(或者使用外部预处理器来处理代码,就像这里建议的那样 Python 相当于#ifdef DEBUG 或这里 如何在 python 中实现“#ifdef”?| ||) 我想在模块的开头定义一个变量 如果需要的话我可以轻松地从 False 更改为 True。然后,我的日志记录代码如下所示:
_verbose_debugging = False
但是,我想要的是,如果它设置为“False”,则在生成的字节码中完全省略调试,类似于
if _verbose_debugging:
print("something resource intensive")
功能。但是,我确实
__debug__
不想
想要使用
,因为它默认打开并且会导致其他冲突。
__debug__
有没有办法告诉CPython字节码编译器我的变量
永远不会在解释器运行时发生变化,如果它曾经见过
_verbose_debugging
那里一次,它可以安全地优化它?
False
我读了很多Stackoverflow文章并研究了
的内部行为(不幸的是,这似乎是“神奇的”) ”)。
__debug__
(which unfortunately seems to be "magic").
你不能完全做你想做的事。 CPython 编译器不会对可以在运行时更改的变量进行假设。
但是,你可以实现类似的目标,有一些缺点:
1. 使用函数
你可以把你的调试代码放在一个函数里,然后根据
_verbose_debugging
的值调用这个函数:
_verbose_debugging = False
def debug_print(message):
if _verbose_debugging:
print(message)
# ... 你的代码 ...
debug_print("something resource intensive")
如果
_verbose_debugging
是
False
,这个方法仍然会产生函数调用的开销,但这比原始代码要小得多。
2. 使用
ast
模块进行预处理
你可以使用 Python 的
ast
模块编写一个预处理器,在编译时删除调试代码。 这个方法更复杂,但可以完全消除运行时开销。
这是一个简单的例子:
import ast
class RemoveDebugging(ast.NodeTransformer):
def visit_Call(self, node):
if isinstance(node.func, ast.Name) and node.func.id == 'debug_print':
return ast.Constant(value=None)
return node
code = """
_verbose_debugging = False
def debug_print(message):
if _verbose_debugging:
print(message)
debug_print("This will be removed")
"""
tree = ast.parse(code)
transformer = RemoveDebugging()
transformer.visit(tree)
ast.fix_missing_locations(tree)
compiled_code = compile(tree, '<string>', 'exec')
exec(compiled_code)
在这个例子中,
RemoveDebugging
类会找到所有对
debug_print
的调用,并将它们替换成
None
。
重要的是要注意
,这些方法仍然依赖于在代码中设置
_verbose_debugging
的值。 它们不会在字节码级别神奇地优化代码。
总的来说,虽然你不能完全复制 C 风格的
#ifdef
行为,但你可以使用这些技术最小化调试代码的性能影响。 选择最适合你的项目的那个。