python/sage:如何获取最后一个表达式?
如果我在Jupiter(无论是用Python还是Sage)里做一些事情,比如:
a = 42
b = 43
a + b
它会以某种方式理解这个过程返回的值是 a + b
,也就是这里的85:
同样,如果我只是这样做:
a = 42
它会理解这里没有什么需要返回的。
现在我想为一个不同的应用做类似的事情(缓存一个Python操作的结果)……我该如何获取这个信息,理想情况下只需运行代码并添加一些Python代码来获得这个信息?我尝试做:
a = 42
b = 43
a + b
print(_)
但这失败了。我在想做一些简单的事情,比如在最后一行前面加上 res =
,但如果最后一行缩进了,这可能会失败……我该如何优雅地获取这个信息呢?
2 个回答
在使用 ipython
的时候,有几种方法可以引用之前的 out
行:
In [113]: a = 42
...: b = 43
...: a + b
Out[113]: 85
In [114]: _ # also __ and ___
Out[114]: 85
In [115]: _113
Out[115]: 85
In [116]: Out[113]
Out[116]: 85
Out
是一个值的列表
如果你想引用一个在单元格中没有被赋值的行,是没有办法做到的:
a = 42
b = 43
a + b
print(?)
使用 a+b;
也会抑制最后的显示/保存,这和执行 c = a+b
是一样的。
_
在普通的交互式 Python 会话中也能使用。jupyter/ipython 对这个历史记录的收集进行了增强。
我觉得这个问题之前已经在一个标题为“获取类似于Jupyter行为的Python变量的值和类型”的帖子中被问过了,发帖者已经在解决方案上取得了很大进展。
最终的方法是使用Python的exec()
函数,先运行代码行,然后用eval()
函数来计算最后一个表达式,就像Jupyter在默认设置下对InteractiveShell.ast_node_interactivity
所做的那样。
我会在这里对我的答案进行一些修改和调整,以适应这里的具体代码情况:
lines = """a = 42
b = 43
a + b"""
exec(lines,globals(),locals())
print(eval(lines.split("\n")[-1]))
这会按预期打印出85
的结果。
发帖者提到一个关于缩进的担忧。确实,我注意到我现在提出的解决方案在最后一行有缩进时会失败。不过我相信可以解决这个问题。如果最后一行有任何程度的缩进,我可以收集之前的行,直到缩进回到最外层的水平。然后用这些收集的行作为“最后一个表达式”来计算。不过我在这里没有这样做,因为不实现这一部分的解决方案已经相当清晰,我不想让它变得更加复杂。
确保阅读关于exec()
和eval()
的警告,详细信息可以在我最初发布这个方法的地方找到。
针对一个评论,我还想强调,在答案中你可以进一步丰富功能,或者以其他方式结合Jupyter/IPython的能力到Python中,因为你可以进行导入。在我在“如何构建一个Python函数,其中输入是Python代码,输出是IPython丰富输出(HTML)?”这个线程中的答案里,我有一个部分叫“针对第一个评论的更新:”,我谈到了在Python中作为导入使用IPython来捕获RichOutput,这个方法在一个演示中进一步展开,展示了你可以利用IPython在Jupyter中使用的方法和函数进行的一些技巧。
*(我最终在这里调整了我之前的答案,因为我把它转移到这里。重新审视我在那里的答案时发现了一个问题,我没有正确分割以获取实际的最后一行进行计算。上次我运气好,原答案的最后一行只有一个字符,所以最后一行和最后一个字符在原始情况下是相同的。我现在也在那边修复了这个问题。)