gpt4 book ai didi

Python代码: Information on Execution Trace of loops/conditionals

转载 作者:行者123 更新时间:2023-12-04 02:26:43 25 4
gpt4 key购买 nike

我想根据完成时执行的循环和条件来获取 python 函数的执行跟踪。但是,我想在不使用附加参数检测原始 python 函数的情况下执行此操作。例如:

def foo(a: int, b: int):
while a:
a = do_something()
if b:
a = do_something()


if __name__ == "__main__":
foo(a, b)
foo()执行后我想要一个执行跟踪,例如: [while: true, if:false, while: true, if: true, while: false, ...]它记录了代码中条件评估的顺序。有没有办法为任意 python 函数自动获取这些信息?
我了解“覆盖”python 模块返回“分支覆盖”信息。但我不确定如何在这种情况下使用它?

最佳答案

您可以使用 trace_conditions.py 作为起点并在需要时对其进行修改。
例子foo问题中定义的函数在以下示例中使用:

from trace_conditions import trace_conditions

# (1) This will just print conditions
traced_foo = trace_conditions(foo)
traced_foo(a, b)
# while c -> True
# if d -> True
# ...

# (2) This will return conditions
traced_foo = trace_conditions(foo, return_conditions=True)
result, conditions = traced_foo(a, b)
# conditions = [('while', 'c', True), ('if', 'd', True), ...)]
备注 : ast.unparse用于获取条件的字符串表示。它是在 Python 3.9 中引入的。如果您想使用旧版本的 Python,也许您需要安装 3rd 方包 astunparse然后在函数 _condition_to_string中使用它.否则 trace_conditions不会返回条件的字符串表示。
TL;博士
主意
基本上,我们希望以编程方式将捕获器添加到函数的代码中。例如, print捕手可能看起来像这样:
while x > 5:
print('while x > 5', x > 5) # <-- print condition after while
# do smth

print('if x > 5', x > 5) # <-- print condition before if
if x > 5:
# do smth
因此,主要思想是在python中使用代码自省(introspection)工具( inspectastexec)。
执行
这里我简单解释一下 trace_conditions.py中的代码:
主要功能 trace_conditions主要功能不言自明,简单地反射(reflect)了整个算法:(1)构建句法树; (2) 注入(inject)条件捕捉器; (3) 编译新函数。
def trace_conditions(
func: Callable, return_conditions=False):
catcher_type = 'yield' if return_conditions else 'print'

tree = _build_syntactic_tree(func)
_inject_catchers(tree, catcher_type)
func = _compile_function(tree, globals_=inspect.stack()[1][0].f_globals)

if return_conditions:
func = _gather_conditions(func)
return func
唯一需要解释的是 globals_=inspect.stack()[1][0].f_globals .为了编译一个新函数,我们需要为 python 提供该函数使用的所有模块(例如,它可能使用 mathnumpydjango 等...)。和 inspect.stack()[1][0].f_globals只需获取调用函数模块中导入的所有内容。
警告!
# math_pi.py
import math

def get_pi():
return math.pi


# test.py
from math_pi import get_pi
from trace_conditions import trace_conditions

traced = trace_conditions(get_pi)
traced() # Error! Math is not imported in this module
要解决它,您可以修改 trace_conditions.py 中的代码或添加 import mathtest.py_build_syntactic_tree
这里我们首先使用 inspect.getsource 获取函数的源代码然后使用 ast.parse 在语法树中解析它.不幸的是,如果从 decorator 调用,python 无法检查函数的源代码。 ,所以用这种方法似乎不可能使用方便的装饰器。
_inject_catchers
在这个函数中,我们遍历给定的句法树,找到 whileif语句,然后在它们之前或之后注入(inject)捕获器。 ast模块有方法 walk ,但它只返回节点本身(没有父节点),所以我实现了 walk 的略微更改版本也返回父节点。如果我们想在 if 之前插入捕手,我们需要知道父级。 .
def _inject_catchers(tree, catcher_type):
for parent, node in _walk_with_parent(tree):
if isinstance(node, ast.While):
_catch_after_while(node, _create_catcher(node, catcher_type))
elif isinstance(node, ast.If):
_catch_before_if(parent, node, _create_catcher(node, catcher_type))
ast.fix_missing_locations(tree)
最后我们调用 ast.fix_missing_locations有助于正确填写技术领域的功能,如 lineno以及编译代码所需的其他内容。通常,您需要在修改句法树时使用它。
捕捉 elif陈述
有趣的是,python 在它的 ast 语法中没有 elif声明,所以它只有 if-else陈述。 ast.If节点有字段 body包含 if 的表达式 body 和场 orelse包含 else 的表达式堵塞。和 elif case 简单地用 ast.If 表示 orelse 内的节点 field 。这一事实反射(reflect)在函数 _catch_before_if 中。 .
捕手(和 _gather_conditions)
有几种方法可以捕获条件,最简单的就是 print它,但如果你想稍后在 python 代码中处理它们,这种方法将不起作用。一种直接的方法是有一个全局空列表,您将在函数执行期间在其中附加条件及其值。但是,我认为这个解决方案在命名空间中引入了一个新名称,这可能会与函数内部的本地名称混淆,所以我认为 yield 应该更安全。条件及其信息。
函数 _gather_conditions正在使用注入(inject)的函数添加包装器 yield语句,它只是收集所有产生的条件并返回函数和条件的结果。

关于Python代码: Information on Execution Trace of loops/conditionals,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67091735/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com