在(中间)代码的任意位置开始Python跟踪?



考虑以下代码,test.py:

import sys, os
import time
import urllib.request

with urllib.request.urlopen('http://www.example.com/') as f:
html = f.read().decode('utf-8')
print("A: {}".format(time.time()))
time.sleep(2)
print("B: {}".format(time.time()))

如果我像往常一样运行,我得到这样的输出:

$ python3 test.py
A: 1634285044.6374931
B: 1634285046.6485002

现在,假设我想跟踪代码-从time.sleep(2)语句之前开始。我不知道这是怎么做到的,但是一个典型的"追踪"。可以在命令行启动,如下所示:

$ python3 -m trace --trace test.py
--- modulename: test, funcname: <module>
test.py(1): import sys, os
test.py(2): import time
test.py(3): import urllib.request
--- modulename: _bootstrap, funcname: _find_and_load
<frozen importlib._bootstrap>(1004):  --- modulename: _bootstrap, funcname: __init__
<frozen importlib._bootstrap>(153): <frozen importlib._bootstrap>(154):  --- modulename: _bootstrap, funcname: __enter__
<frozen importlib._bootstrap>(157):  --- modulename: _bootstrap, funcname: _get_module_lock
<frozen importlib._bootstrap>(172): <frozen importlib._bootstrap>(173): <frozen importlib._bootstrap>(174): <frozen importlib._bootstrap>(175): <frozen importlib._bootstrap>(176): <frozen importlib._bootstrap>(177): <frozen importlib._bootstrap>(179): <frozen importlib._bootstrap>(180): <frozen importlib._bootstrap>(183):  --- modulename: _bootstrap, funcname: __init__
<frozen importlib._bootstrap>(59): <frozen importlib._bootstrap>(60): <frozen importlib._bootstrap>(61): <frozen importlib._bootstrap>(62): <frozen importlib._bootstrap>(63): <frozen importlib._bootstrap>(64): <frozen importlib._bootstrap>(185): <frozen importlib._bootstrap>(196): <frozen importlib._bootstrap>(198): <frozen importlib._bootstrap>(200): <frozen importlib._bootstrap>(158):  --- modulename: _bootstrap, funcname: acquire
...

…但是输出-至少对于进口和urlopen()-是巨大的,这使得极其很难看到发生了什么!

顺便说一句,如果您注释了import urllib.requestwith urllib.request.urlopen ...行,那么跟踪就是这样的:
$ python3 -m trace --trace test.py
--- modulename: test, funcname: <module>
test.py(1): import sys, os
test.py(2): import time
test.py(9): print("A: {}".format(time.time()))
A: 1634285323.556725
test.py(11): time.sleep(2)
test.py(13): print("B: {}".format(time.time()))
B: 1634285325.5598364
test.py(775): """

所以,理想情况下,我会有一个工具,允许我在代码的中间(或者更确切地说,在任意位置)开始跟踪;下面的伪代码示例:

import sys, os
import time
import urllib.request

with urllib.request.urlopen('http://www.example.com/') as f:
html = f.read().decode('utf-8')
print("A: {}".format(time.time()))

# I'd want the line-by-line tracing to start here; so:
import trace; trace.START_TRACE()
time.sleep(2)
print("B: {}".format(time.time()))

在Python 3中有这样做的工具吗?

是的,所以在@user2357112supportsMonica的评论之后,我查看了trace模块cpython/trace.py的源代码3.10·python/cpython -我可以看到,它基本上编译了脚本代码(这就是为什么在中间进行干预会很棘手)-但是,它也使用sys.settrace

所以,我看了更多,并找到了如何为sys.settrace制作自定义跟踪器函数的示例-并且可以将OP示例修改为:

import sys, linecache                   # add
# mytrace function based on https://stackoverflow.com/questions/63927342/limit-data-returned-by-sys-settrace
def mytrace(frame, event, arg_unused):  # add
filename = frame.f_code.co_filename
lineno = frame.f_lineno
print((event, filename, lineno, linecache.getline(filename, lineno)) ) # frame.f_locals
return mytrace
import sys, os
import time
import urllib.request

with urllib.request.urlopen('http://www.example.com/') as f:
html = f.read().decode('utf-8')
# START TRACING
# https://stackoverflow.com/questions/65350552/sys-settrace-seems-to-be-ignored-in-threads
# https://stackoverflow.com/questions/55998616/how-to-trace-code-run-in-global-scope-using-sys-settrace
sys._getframe().f_trace = mytrace
sys.settrace(mytrace)
print("A: {}".format(time.time()))
time.sleep(2)
# STOP TRACING
sys.settrace(None)
print("B: {}".format(time.time()))

然后,当你运行这段代码时:

$ python3 test.py
('line', '/tmp/test.py', 23, 'print("A: {}".format(time.time()))n')
A: 1634290271.2226915
('line', '/tmp/test.py', 25, 'time.sleep(2)n')
('line', '/tmp/test.py', 28, 'sys.settrace(None)n')
B: 1634290273.228311

很好-正是我想要的!

相关内容

  • 没有找到相关文章

最新更新