3

对不起那种一般性的问题。关于我想要的更多细节:

我希望用户能够编写一些 Python 代码并执行它。一旦出现未处理的异常,我希望调试器暂停执行,显示有关当前状态/环境/堆栈/异常的信息,并使编辑代码成为可能。

我只想让特殊代码块在发生异常的地方可编辑,而不是其他(暂时)。即如果它发生在for循环内,我只想让for循环内的代码块可编辑。它应该是用户编辑器范围内的最新/最新代码块(而不是在其他一些库或 Python 库中)。在这种情况下,总是很清楚要编辑什么代码块。


我已经尝试过研究如何做到这一点,尽管我感到有点失落。

Python 回溯没有直接给我代码块,只是函数和代码行。我可以计算回来,但这对我来说似乎有点老套。如果我能以某种方式在代码的 AST 中获得对代码块的引用,则更好(也更自然)。

要获得 AST(并对其进行操作,即操作/编辑),我可能会使用compiler(已弃用?)和/或parser模块。或者ast模块。不确定如何重新编译 AST 中的特殊节点/代码块。或者,如果我只能重新编译整个函数。

4

3 回答 3

2

玩弄astand compile(内置)似乎您可以使用NodeTransformer来修改某些节点...如果您知道要查找的内容,也可以手动编辑它们。

测试.py

print 'Dumb Guy'
x = 4 + 4
print x * 3

改变.py

import ast
with open('test.py') as f:
    expr = f.read()

e = ast.parse(expr)
e.body[0].values[0].s = 'Cool Guy'       # Replace the string
e.body[1].targets[0].id = 'herring'      # Change x to herring
e.body[2].values[0].left.id = 'herring'  # Change reference to x to reference to herring
c = compile(e, '<string>', 'exec')
exec(c)

change.py 的输出:

酷家伙
24

您也可以通过这种方式将代码添加到正文中(或以通常替换列表元素的方式替换元素):

p = ast.parse('print "Sweet!"', mode='single')
e.body.extend(p)

然后重新编译并执行:

c = compile(e, '<string>', 'exec')
exec(c)

您可以通过这种方式替换函数定义或单行。函数定义将有自己的主体,因此如果您添加了一些函数(或循环),您可以使用

e.body[N].body  # Replace N with the index of the FunctionDef object

但是,我知道执行单个 ast 对象(_ast.Print_ast.Assign其他对象)的唯一方法是执行以下操作:

e2 = ast.parse('', mode='exec')
e2.body.append(e.body[0])
exec(compile(e2, '<string>', 'exec'))

这对我来说似乎有点骇人听闻。就行而言 - AST 中的每个对象都有一个lineno属性,因此如果您可以从异常中检索行号,您可以很容易地找出哪个语句引发了异常。

当然,这并不能真正解决将堆栈回退到异常前状态的问题,这听起来是你真正想做的事情。但是,可以通过pdb来做这样的事情。

于 2010-07-12T15:27:29.420 回答
1

我想知道适用于 Python 的 HAP 远程调试器是否对您有用?我不认为他们有实时编辑,但一些调试方面可能仍然有用。

于 2010-07-12T16:42:25.150 回答
1

根据我在此期间的了解,这是不可能的。至少不是分块。可以按函数重新编译代码,但不能按代码块重新编译代码,因为 Python 会为每个函数生成代码对象。

所以唯一的办法就是写一个自己的 Python 编译器。

于 2010-08-17T00:37:48.010 回答