什么是Python相当于壳`设置-x`的?(What is the Python equivalen

2019-08-18 23:25发布

请建议Python的命令,它等价的set -x的shell脚本。

有没有一种方法来打印/日志被Python执行的每个源文件行?

Answer 1:

您可以使用跟踪模块:

python -m trace -t your_script.py

在命令行,因为它是执行上述将显示的每行代码。



Answer 2:

得到的一个适当的等效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



Answer 3:

我喜欢@ 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.pyfile2.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


文章来源: What is the Python equivalent of `set -x` in shell?