请建议Python的命令,它等价的set -x
的shell脚本。
有没有一种方法来打印/日志被Python执行的每个源文件行?
请建议Python的命令,它等价的set -x
的shell脚本。
有没有一种方法来打印/日志被Python执行的每个源文件行?
您可以使用跟踪模块:
python -m trace -t your_script.py
在命令行,因为它是执行上述将显示的每行代码。
得到的一个适当的等效bash -x
使用trace
模块,一个需要使用--ignore-dir
到框的每一个导入的模块,例如源极线的印刷python -m trace --trace --ignore-dir /usr/lib/python2.7 --ignore-dir /usr/lib/pymodules repost.py
,增加更多的--ignore-dir
根据需要为其它模块的位置的指令。
这种尝试定位慢加载模块,如时变得重要requests
其吐出数百万的源代码行的慢的机器上几分钟。 正确使用--ignore-dir
切割时间缩短到几秒钟,并且只显示从您自己的代码行。
$ time python -m trace --trace repost.py 2>&1 | wc
3710176 16165000 200743489
real 1m54.302s
user 2m14.360s
sys 0m1.344s
与
$ time python -m trace --trace --ignore-dir /usr/lib/python2.7 --ignore-dir /usr/lib/pymodules repost.py 2>&1 | wc
42 210 2169
real 0m12.570s
user 0m12.421s
sys 0m0.108s
这并没有真正回答你的问题; 你问一个Python等同的set -x
。 一个简单的方法来近似地认为是sys.settrace()
jcomeau@aspire:/tmp$ cat test.py
#!/usr/bin/python -OO
'''
test program for sys.settrace
'''
import sys, linecache
TRACING = []
def traceit(frame, event, arg):
if event == "line":
lineno = frame.f_lineno
line = linecache.getline(sys.argv[0], lineno)
if TRACING:
print "%d: %s" % (lineno, line.rstrip())
return traceit
def test():
print 'this first line should not trace'
TRACING.append(True)
print 'this line and the following ought to show'
print "that's all folks"
TRACING.pop()
print 'this last line should not trace'
if __name__ == '__main__':
sys.settrace(traceit)
test()
其中,在运行时,给出了:
jcomeau@aspire:/tmp$ ./test.py
this first line should not trace
19: print 'this line and the following ought to show'
this line and the following ought to show
20: print "that's all folks"
that's all folks
21: TRACING.pop()
this last line should not trace
消除来自跟踪输出的线“TRACING.pop()”被留给读者作为练习读者。
来源: https://pymotw.com/2/sys/tracing.html和http://www.dalkescientific.com/writings/diary/archive/2005/04/20/tracing_python_code.html
我喜欢@ jcomeau_ictx的答案非常多,但它有一个小缺陷,这就是为什么我在这延长了一下。 问题是,jcomeau_ictx的“traceit”功能只有正常工作,如果要跟踪所有的代码是调用文件中的python file.py
(姑且称之为主机文件)。 如果调用任何导入的功能,你可以得到很多的行号的无代码。 这样做的原因是, line = linecache.getline(sys.argv[0], lineno)
总是试图从主机文件得到的代码行( sys.argv[0]
这很容易被纠正,因为这实际上包含的代码追踪线中可以找到该文件的名称frame.f_code.co_filename
。 现在,这可能会产生大量的输出,这就是为什么一个可能会希望有更多的控制。
还有另一位注意到。 按照sys.settrace()
文档:
跟踪功能调用(与事件设置为“呼叫”),每当进入一个新的本地范围
换句话说,要跟踪的码必须是一个函数内。
东西都保持整洁,我决定把一切都变成称为自己的文件setx.py
。 该代码应该是不言自明。 有,然而,一个代码片段所需要的Python 3的相容性,其与相对于模块如何导入Python 2和3之间的差异的交易。 这说明在这里 。 该代码现在应该也与Python 2和3都工作。
##setx.py
from __future__ import print_function
import sys, linecache
##adapted from https://stackoverflow.com/a/33449763/2454357
##emulates bash's set -x and set +x
##for turning tracing on and off
TRACING = False
##FILENAMES defines which files should be traced
##by default this will on only be the host file
FILENAMES = [sys.argv[0]]
##flag to ignore FILENAMES and alwas trace all files
##off by default
FOLLOWALL = False
def traceit(frame, event, arg):
if event == "line":
##from https://stackoverflow.com/a/40945851/2454357
while frame.f_code.co_filename.startswith('<frozen'):
frame = frame.f_back
filename = frame.f_code.co_filename
## print(filename, FILENAMES)
if TRACING and (
filename in FILENAMES or
filename+'c' in FILENAMES or
FOLLOWALL
):
lineno = frame.f_lineno
line = linecache.getline(filename, lineno)
print("{}, {}: {}".format(filename, lineno, line.rstrip()))
return traceit
sys.settrace(traceit)
然后我测试这个代码的功能:
##setx_tester.py
from __future__ import print_function
import os
import setx
from collections import OrderedDict
import file1
from file1 import func1
import file2
from file2 import func2
def inner_func():
return 15
def test_func():
x=5
print('the value of x is', x)
##testing function calling:
print('-'*50)
##no further settings
print(inner_func())
print(func1())
print(func2())
print('-'*50)
##adding the file1.py to the filenames to be traced
##it appears that the full path to the file is needed:
setx.FILENAMES.append(file1.__file__)
print(inner_func())
print(func1())
print(func2())
print('-'*50)
##restoring original:
setx.FILENAMES.pop()
##setting that all files should be traced:
setx.FOLLOWALL = True
print(inner_func())
print(func1())
print(func2())
##turn tracing on:
setx.TRACING = True
outer_test = 42 ##<-- this line will not show up in the output
test_func()
该文件file1.py
和file2.py
是这样的:
##file1.py
def func1():
return 7**2
和
##file2.py
def func2():
return 'abc'*3
然后输出如下:
setx_tester.py, 16: x=5
setx_tester.py, 17: print('the value of x is', x)
the value of x is 5
setx_tester.py, 20: print('-'*50)
--------------------------------------------------
setx_tester.py, 22: print(inner_func())
setx_tester.py, 12: return 15
15
setx_tester.py, 23: print(func1())
49
setx_tester.py, 24: print(func2())
abcabcabc
setx_tester.py, 26: print('-'*50)
--------------------------------------------------
setx_tester.py, 29: setx.FILENAMES.append(file1.__file__)
setx_tester.py, 30: print(inner_func())
setx_tester.py, 12: return 15
15
setx_tester.py, 31: print(func1())
**path to file**/file1.py, 2: return 7**2
49
setx_tester.py, 32: print(func2())
abcabcabc
setx_tester.py, 34: print('-'*50)
--------------------------------------------------
setx_tester.py, 36: setx.FILENAMES.pop()
setx_tester.py, 39: setx.FOLLOWALL = True
setx_tester.py, 40: print(inner_func())
setx_tester.py, 12: return 15
15
setx_tester.py, 41: print(func1())
**path to file**/file1.py, 2: return 7**2
49
setx_tester.py, 42: print(func2())
**path to file**/file2.py, 2: return 'abc'*3
abcabcabc