逐步跟踪Python表达式求值

逐步跟踪Python表达式求值,python,abstract-syntax-tree,Python,Abstract Syntax Tree,我正在尝试编写Python表达式评估可视化工具,它将逐步显示Python表达式是如何评估的(出于教育目的)。Philip Guo的Python教程很棒,但它逐行评估Python程序,我发现学生有时不理解如何评估像排序([4,2,3,1]+[5,6])[1]==2这样的单行表达式,我希望将此过程可视化。(似乎还没有人这么做——至少我什么也没发现。)理想的解决方案将创建如下字符串序列: sorted([4, 2, 3, 1] + [5, 6])[1] == 2 sorted( >> [4

我正在尝试编写Python表达式评估可视化工具,它将逐步显示Python表达式是如何评估的(出于教育目的)。Philip Guo的Python教程很棒,但它逐行评估Python程序,我发现学生有时不理解如何评估像
排序([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
排序([4,2,3,1]+[5,6])[1]==2

已排序(>>[4,2,3,1]+[5,6]>已排序([4,2,3,1,5,6])>[123456][1]>2==2>
添加这两个列表肯定不是该代码中要评估的第一个节点;我相信事实上有九个早期节点评估-
排序
4
2
3
1
[4,2,3,1]
5
6
[5,6]
。您不仅需要确定执行评估的顺序,还需要确定哪些评估值得显示


我认为解决您的问题的更好方法是修改AST节点,使其作为执行的副作用发出其前/后状态。您不必关心它们的顺序,只需执行整个表达式一次。并且已经有一个名为的包,它具有跟踪功能,可准确执行此操作。其输出不受限制不完全符合您的要求,但它可能会被修改为更接近匹配。

为什么不使用
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

表达式步进在中实现

它使用AST指令插入,其中每个(子)表达式
e
被转换为
after(before(),e)
。函数
before
after
是在Python跟踪系统中引起额外调用事件的伪函数。这些额外调用在(子)时通知表达式计算即将开始或刚刚结束。(添加了类似的伪函数以检测每个语句的开始和结束。)

AST仪器和这些新事件的解释在中完成

Python的AST节点包含相应文本范围的起始位置,但它们有时不正确。结束位置完全丢失。尝试解决此问题(但目前解决方案不完整)


如果有人将Thonny的相关功能提取到一个更通用的包中,那就太好了。甚至可能有两个包——一个用于计算Python AST的位置信息,另一个用于详细跟踪Python代码。如果有人带头,我愿意在这方面提供帮助。

Hm-m,
macropy
看起来非常接近,而且很有希望,谢谢。我必须深入研究一下。从技术上讲,这是正确的。然而,我的问题的目的是制作一个工具,帮助我在学生们开始学习Python的第一步时,当他们刚刚熟悉软件编程的基本概念时,教给他们。这不是计算机科学学生,Python是他们的工具,而不是o科学感兴趣的对象。因此,向他们展示字节码作为问题的答案是绝对不可能的。也许,可以通过某种方式解析字节码,以可访问的术语重建过程,但这似乎并不简单。@IlyaV.Schurov,因为你在教学生“第一步”在Python中,为什么要“揭下盖子”呢?既然我是一名接受过培训的机械工程师,使用Python作为工具,我想我可以说,非计算机科学家有可能了解Python的工作原理。:-)当然这是可能的。我也不是计算机科学家:)但我认为一开始我们并不真的需要它。这有点像“在你能够登录Facebook之前,你必须学习架构x86、汇编、C、TCP/IP协议、HTTP协议、HTML、CSS和Javascript。然后发布你的照片。哦,停下来,我们忘记了JPEG”。不管怎样,谢谢你的想法,这很好。至于编辑,事实上这或多或少是我现在教他们的方式。然而,我想给学生们一个机会,让他们自己用代码做实验,所以我正在寻找一些编程解决方案。