繁体   English   中英

逐步跟踪Python表达式评估

Tracing Python expression evaluation step by step

提示:本站收集StackOverFlow近2千万问答,支持中英文搜索,鼠标放在语句上弹窗显示对应的参考中文或英文, 本站还提供   中文繁体   英文版本   中英对照 版本,有任何建议请联系yoyou2525@163.com。

我正在尝试编写Python表达式评估可视化工具,它将显示如何逐步评估Python表达式(用于教育目的)。 Philip Guo的Python Tutor很棒,但它逐行评估Python程序,我发现学生有时候不理解单行表达式如何sorted([4, 2, 3, 1] + [5, 6])[1] == 2进行评估,我想想象这个过程。 (似乎没有人做过 - 至少我什么也没发现。)理想的解决方案是创建一系列字符串,如下所示:

sorted([4, 2, 3, 1] + [5, 6])[1] == 2
sorted( >> [4, 2, 3, 1] + [5, 6] << )[1] == 2
>> sorted([4, 2, 3, 1, 5, 6]) << [1] == 2
>> [1 2 3 4 5 6][1] << == 2
>> 2 == 2 <<
True

这里>><<用于突出显示在当前步骤上计算的表达式的一部分,然后由其值替换。 (也许,我会尝试将此序列转换为某种动画。)

我当前的策略是使用ast.parse()将字符串解析为AST,然后找到一个将首先评估的eval(compile(node, '', 'eval'))eval(compile(node, '', 'eval'))进行eval(compile(node, '', 'eval')) (我肯定是不想重新实现整个Python :)),将评估结果转换为AST Node(用repr然后ast.parse() ?)并用结果节点替换当前节点,然后使用codegen.to_source生成修改后的代码来自(已修改)AST的字符串并继续相同的过程,直到我在树中只有一个文字。

我的问题是:如何找到首先评估的节点? 似乎我可以通过子类化ast.NodeVisitor来遍历树的深度ast.NodeVisitor ,但是我不知道如何检测到我到达了所需的节点以及如何在它之后停止遍历?


编辑。

我对树的转换的初始方法可能是不可行的。 事实上,评估Python表达式的基本步骤不是必须将某个子表达式替换为更简单的表达式(如算术中)。 例如,列表推导提供了一个更复杂的行为,无法用术语替换这个东西,然后递归重复 所以我稍微重申了一个问题。 我需要一些方法来programmaticaly显示如何逐步评估Python表达式。 例如,@ jasonharper提到的MacroPy的跟踪功能在此阶段是可接受的解决方案。 不幸的是,MacroPy似乎被放弃了,并且不适用于Python 3.在没有移植完整的MacroPy的情况下,有没有想法如何在Python 3中类似这种跟踪行为?


EDIT2。

在我获得此奖金之后,我发现了类似的问题和一个具有非常接近功能的调试器 但是,由于这个问题没有最终答案,而且我不需要完整的调试器,我仍然在寻找可以在Jupyter环境中使用的答案。

3 个回复

表达式步进在Thonny IDE中实现。

它使用AST检测,其中每个(子)表达式e被转换为after(before(<location info>), e) beforeafter的函数是用于在Python的跟踪系统中引起额外调用事件的虚函数。 当(子)表达式评估即将开始或刚刚结束时,这些额外调用会通知。 (添加类似的虚函数来检测每个语句的开始和结束。)

这些新事件的AST检测和解释在thonny.backend.FancyTracer中完成。

Python的AST节点包含相应文本范围的起始位置,但它们有时不正确。 结束位置完全缺失。 thonny.ast_utils.mark_text_ranges试图解决这个问题(但目前解决方案尚未完成)。

如果有人从Thonny中提取相关功能到一个更通用的包,那将是很好的。 甚至可能是两个包 - 一个用于计算Python AST的位置信息,另一个用于详细跟踪Python代码。 如果有人带头,我愿意帮忙。

为什么不使用dis模块?

由于CPython将Python编译为字节码并运行它,因此查看字节码可以让您最好地了解实际发生的情况。

In [1]: import dis

In [2]: dis.dis('sorted([4, 2, 3, 1] + [5, 6])[1] == 2')
  1           0 LOAD_NAME                0 (sorted)
              3 LOAD_CONST               0 (4)
              6 LOAD_CONST               1 (2)
              9 LOAD_CONST               2 (3)
             12 LOAD_CONST               3 (1)
             15 BUILD_LIST               4
             18 LOAD_CONST               4 (5)
             21 LOAD_CONST               5 (6)
             24 BUILD_LIST               2
             27 BINARY_ADD
             28 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
             31 LOAD_CONST               3 (1)
             34 BINARY_SUBSCR
             35 LOAD_CONST               1 (2)
             38 COMPARE_OP               2 (==)
             41 RETURN_VALUE

编辑 :另一种方法可能是在IPython中逐个显示步骤:

In [1]: [4, 2, 3, 1]
Out[1]: [4, 2, 3, 1]

In [2]: [4, 2, 3, 1] + [5, 6]
Out[2]: [4, 2, 3, 1, 5, 6]

In [3]: sorted([4, 2, 3, 1, 5, 6])
Out[3]: [1, 2, 3, 4, 5, 6]

In [4]: [1, 2, 3, 4, 5, 6][1]
Out[4]: 2

In [5]: 2 == 2
Out[5]: True

添加两个列表肯定不是该代码中要评估的第一个节点; 相信有实际上9分前面节点的评价- sorted4231[4,2,3,1] 56[5,6] 您不仅需要确定执行哪些订单评估,还必须决定哪些评估值得展示。

我认为更好的方法是修改AST节点,使它们发出前/后状态作为执行的副作用。 你不会关心他们的顺序,你只需执行一次整个表达式。 并且已经有一个名为macropy的软件包具有跟踪功能,可以完成此操作。 它的输出并不是你所要求的,但它可能会被修改为更接近的匹配。

1 如何逐步完成Python表达式评估过程?

我想构建一个可视化调试器,它可以帮助编程学生了解表达式评估是如何进行的(子表达式如何通过它们的值进行评估和“替换”,例如Excel中的表达式评估可视化器)。 看起来你不能用Python的pdb来完成这个过程,因为它最好的步骤粒度就是代码行。 是否有可能逐步通过Python字节码? 任何 ...

4 迭代表达式的python评估

我有一个数据库,如果 k 个连续数字使得以下数字高于第二个数字,我想创建一个值为 1 的列。 我写了以下内容,但出现语法错误 我应该使用哪个代码? 编辑 1: 我想要一个比下面更紧凑的代码,这是 k=5 ...

5 python如何评估“是”表达式? [重复]

这个问题在这里已有答案: “是”运算符与整数 11个答案 意外地表现 python中“is”表达式的不稳定行为。 和 python如何评估“是”表达式? 为什么它显示为假,尽管它是真的? 为什么它只发生在某些数字上? ...

2013-05-17 18:44:39 4 261   python
6 python尝试除了作为评估表达式的函数

我尝试创建一个函数,该函数尝试表达式并在出现错误时返回零。 这显然不起作用。 似乎问题在于 python 没有任何形式的惰性求值,因此表达式在传递给函数之前被求值,因此它在进入函数之前引发错误,因此它永远不会通过 try 逻辑。 有谁知道这是否可以在 Python 中完成? 干杯 ...

8 Python表达式评估(“或”)[重复]

这个问题已经在这里有了答案: 布尔型Python值混淆 2个答案 我想知道Python如何计算或使用整数表达式。 互联网研究尚未得出令人满意的答案。 问题1 上面的结果是10,我不明白为什么。 问题2 如何 : False or 1 ...

9 数学表达式的评估出错:Python

我采用了一个函数来评估由数字和数学表达式组成的字符串列表,但无法获得预期的结果。 例如:5 + 2-3 + 2 = 6 基本上,该函数通过初始化结果的第一个数字输入(Inp)的值开始。 然后,它将运算从左到右应用于当前结果,依此类推,直到获得最终结果。 下面是脚本。 ...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2022 STACKOOM.COM