有没有办法获取Python程序的跟踪表?或者一个程序运行另一个程序并获取其跟踪表?我是一名老师,试图完美地验证我们在测试中使用的跟踪问题的答案。
因此,例如,假设我有一个名为problem1.py
的Python程序,其中包含以下内容:
a = 1
b = 2
a = a + b
执行假定的程序traceTable.py
应该如下:
$ python traceTable.py problem1.py
L || a | b
1 || 1 |
2 || 1 | 2
4 || 3 | 2
(或使用不同语法的相同信息)
我查看了trace
模块,我看不到它支持这种方式。
女士们,先生们:使用Ned Batchelder的优秀建议,我给你traceTable.py
!
frame.f_lineno
并不总是直观地表现(例如,第3行和第4行都被计为第4行),但行号足够接近以获得相当好的参考。此外,所有计算都是正确的。
我用一个包含if
语句的长程序测试了它,它给出了正确的表格(没有行号)。
您还会注意到,由于在他提到的较大程序中考虑了“更有趣的数据生态系统”,我的程序比Ned Batchelder的概念验证要长得多。在使用execfile
和管理它所需的所有变量以及降低噪声(ala ignored_variables
)以及生成正确的字符串输出的范围内,需要更多代码:
'''
Usage: python traceTable.py program
-program Python program to be traced
'''
import sys
if len(sys.argv) < 2:
print __doc__
exit()
else:
file_name = sys.argv[1]
past_locals = {}
variable_list = []
table_content = ""
ignored_variables = set([
'file_name',
'trace',
'sys',
'past_locals',
'variable_list',
'table_content',
'getattr',
'name',
'self',
'object',
'consumed',
'data',
'ignored_variables'])
def trace(frame, event, arg_unused):
global past_locals, variable_list, table_content, ignored_variables
relevant_locals = {}
all_locals = frame.f_locals.copy()
for k,v in all_locals.items():
if not k.startswith("__") and k not in ignored_variables:
relevant_locals[k] = v
if len(relevant_locals) > 0 and past_locals != relevant_locals:
for i in relevant_locals:
if i not in past_locals:
variable_list.append(i)
table_content += str(frame.f_lineno) + " || "
for variable in variable_list:
table_content += str(relevant_locals[variable]) + " | "
table_content = table_content[:-2]
table_content += '\n'
past_locals = relevant_locals
return trace
sys.settrace(trace)
execfile(file_name)
table_header = "L || "
for variable in variable_list:
table_header += variable + ' | '
table_header = table_header[:-2]
print table_header
print table_content
调用时,会产生输出
$ python traceTable.py problem1.py
L || a | b
2 || 1
4 || 1 | 2
4 || 3 | 2
答案 0 :(得分:10)
这不是当前Python跟踪工具支持的用例,但应该可以构建。我不知道你如何决定输出哪些列。在您的示例中,a和b是唯一的局部变量,但较大的程序会有更有趣的数据生态系统。
更新:这是一个简单的概念证明:
1 import sys
2
3 def trace(frame, event, arg_unused):
4 print event, frame.f_lineno, frame.f_locals
5 return trace
6
7 sys.settrace(trace)
8
9 def foo():
10 a = 1
11 b = 2
12
13 a = a + b
14
15 foo()
运行时,输出为:
call 9 {}
line 10 {}
line 11 {'a': 1}
line 13 {'a': 1, 'b': 2}
return 13 {'a': 3, 'b': 2}
答案 1 :(得分:0)
您可以使用Python debugger,虽然我不知道如何让它自行完成,但它很可能,但您可以解析输出。
这是一个非常粗略的例子:
<强> adding.py 强>
a = 1
b = 2
a = a + b
运行它......
PS >python -m pdb adding.py
> adding.py(1)<module>()
-> a = 1
(Pdb) alias stepprint step;;print a;;print b
(Pdb) stepprint
> adding.py(2)<module>()
-> b = 2
1
*** NameError: name 'b' is not defined
(Pdb) stepprint
> adding.py(4)<module>()
-> a = a + b
1
2
(Pdb) stepprint
--Return--
> adding.py(4)<module>()->None
-> a = a + b
3
2
(Pdb) stepprint
--Return--
> <string>(1)<module>()->None
3
2
(Pdb) stepprint
The program finished and will be restarted
> adding.py(1)<module>()
-> a = 1
*** NameError: name 'a' is not defined
*** NameError: name 'b' is not defined
(Pdb) q
PS >
结束(q)“程序完成”位。
答案 2 :(得分:0)
根据ned-batchelder提出的建议,作为一名教师,我已经制作了一个LaTeX
课程,帮助创建longtable
输出input()
,显示一个程序的跟踪选择性变量,绕过\bash
进行自动化过程(特别是在强大的害羞LaTeX
包中由import sys
class Tracer():
def __init__(self, varList=[], startLine=1, jeuEssai=[]):
"""
Arguments :
\tvarList\ttraced variable list (used as column header)
\tstartLine\toffset numbering line from the beginning of the program
\tjeuEssai\tinput values to be sent to the automated input bypass
"""
self.traced_variables = varList
self.traced_line_start = startLine
self.input_values = jeuEssai
self.input_cursor = int(0)
self.traced_variables_new_values = dict( (k, '') for k in self.traced_variables)
print("\\begin{longtable}{c*{%i}{>{\\ttfamily}c}}" % len(self.traced_variables), file=sys.stderr, flush=True)
print("\t\\hline\\no ligne",end='', file=sys.stderr)
for header in self.traced_variables:
print(" &", header,end='', file=sys.stderr)
print(" \\\\ \\hline", file=sys.stderr)
sys.settrace(self.tracer_programme_latex)
def tracer_programme_latex(self, frame, event, args):
if frame.f_code.co_name not in ['input','print','close']:
if event == "line":
output = str()
for var in self.traced_variables:
current_val = str(frame.f_locals.get(var, "-"))
if str(self.traced_variables_new_values.get(var, "-")) != current_val:
self.traced_variables_new_values[var] = current_val
current_val = "\hit{}" + current_val
output += " & "
output += current_val
output += " \\\\"
print("\t%s%s" % (str(frame.f_lineno - self.traced_line_start), output), file=sys.stderr, flush=True)
return self.tracer_programme_latex
def close(self):
"""Close the 'longtable' LaTeX environnement."""
print("\\end{longtable}", file=sys.stderr, flush=True)
def input(self, prompt=None):
"""
bypass de la fonction 'input()' pour injecter
les valeurs d'essais.
Le jeu d'essai est fourni de manière cyclique. Cela peut
causer des boucles infinies si vous ne fournissez pas une
valeur permettant de réaliser l'arrêt des entrées (dans le
cas bien-sûr où 'input()' est appelé dans une boucle).
"""
self.input_cursor = (1 + self.input_cursor) % len(self.input_values)
return self.input_values[self.input_cursor - 1]
def print(self, *args):
pass
宏调用时)。
def factor():
question = "Give a number: "
number = float(input(question))
product = 1
while number != 0 :
product *= number
print("Product:", product)
number = float(input(question))
if __name__ == "__main__":
import sys
TRACING = len(sys.argv) == 2 and sys.argv[1] == 'trace'
if TRACING:
from tracer import Tracer
t = Tracer(varList=['question','number','product'], startLine=2, jeuEssai=[7,6,5,-8,0])
input = t.input
factor()
if TRACING:
t.close()
接下来,你可以找到一个例子,并生成输出:
python3 program.py
Give a number: 7
Product: 7.0
Give a number: 6
Product: 42.0
Give a number: 5
Product: 210.0
Give a number: -8
Product: -1680.0
Give a number: 0
调用)python3 program.py trace 1>/dev/null
使用Tracer输出\begin{longtable}{c*{3}{>{\ttfamily}c}}
\hline\no ligne & question & number & product \\ \hline
0 & \hit{}- & \hit{}- & \hit{}- \\
1 & \hit{}Give a number: & - & - \\
2 & Give a number: & \hit{}7.0 & - \\
3 & Give a number: & 7.0 & \hit{}1 \\
4 & Give a number: & 7.0 & 1 \\
5 & Give a number: & 7.0 & \hit{}7.0 \\
6 & Give a number: & 7.0 & 7.0 \\
3 & Give a number: & \hit{}6.0 & 7.0 \\
4 & Give a number: & 6.0 & 7.0 \\
5 & Give a number: & 6.0 & \hit{}42.0 \\
6 & Give a number: & 6.0 & 42.0 \\
3 & Give a number: & \hit{}5.0 & 42.0 \\
4 & Give a number: & 5.0 & 42.0 \\
5 & Give a number: & 5.0 & \hit{}210.0 \\
6 & Give a number: & 5.0 & 210.0 \\
3 & Give a number: & \hit{}-8.0 & 210.0 \\
4 & Give a number: & -8.0 & 210.0 \\
5 & Give a number: & -8.0 & \hit{}-1680.0 \\
6 & Give a number: & -8.0 & -1680.0 \\
3 & Give a number: & \hit{}0.0 & -1680.0 \\
\end{longtable}
调用)\hit{}
值已更改时插入\newcommand{\hit}{\color{red}}
宏。由您来定义相关内容,例如着色宏:CTE