目标是os在下面的代码中解析依赖项并ls执行命令。
我想知道如何用双星做我在下面发表的评论。
我已经知道我可以通过 traceback
也就是说,我想知道是否可以在给定上下文中的给定行号处恢复程序的执行。
import sys
def new_sys_excepthook(type, value, traceback):
if type == NameError:
pass
# Resolution of the exception finding the module dependency and doing the import
# ** Returning to the line that created the exception with the right
# ** context and continue the execution with the module
# ** dependency resolved
# call original excepthook if we can't solve the issue
sys.__excepthook__(type, value, traceback)
sys.excepthook = new_sys_excepthook
system("ls")
Run Code Online (Sandbox Code Playgroud)
执行此类任意跳转的唯一方法是在 CPython 中,并且是名为sys.settrace.
这是一种取自幽默的goto愚人节模块的方法,它可以让我跳到(看似)任意行:
import sys
import inspect
_line_number = None
_frame = None
def jump_to(line_number, frame):
global _line_number, _frame
print("Set jump to line", line_number, "in", inspect.getfile(frame))
_frame = frame
_line_number = line_number
def _trace(frame, event, arg):
global _line_number, _frame
try:
if _line_number is not None:
if inspect.getfile(_frame) == inspect.getfile(frame):
print("Jumping to line", _line_number, "in", inspect.getfile(frame))
frame.f_lineno = _line_number
_line_number = None
except ValueError as e:
print(e)
return _trace
def install():
sys.settrace(_trace)
frame = sys._getframe().f_back
while frame:
frame.f_trace = _trace
frame = frame.f_back
Run Code Online (Sandbox Code Playgroud)
如果我像这样运行它:
import traceh
traceh.install()
import inspect
traceh.jump_to(10, inspect.currentframe())
print(1)
print(2)
print(3)
print(4)
print(5)
print(6)
Run Code Online (Sandbox Code Playgroud)
我得到了令人兴奋的输出:
Set jump to line 10 in tr.py
Jumping to line 10 in tr.py
4
5
6
Run Code Online (Sandbox Code Playgroud)
现在我们可以将其嵌入到 中sys.excepthook,确定吗?
...
def new_sys_excepthook(type, value, traceback):
if type == NameError:
jump_to(traceback.tb_lineno, traceback.tb_frame)
traceback.tb_frame
return
sys.__excepthook__(type, value, traceback)
def install():
sys.excepthook = new_sys_excepthook
sys.settrace(_trace)
...
Run Code Online (Sandbox Code Playgroud)
并使用它:
import traceh
traceh.install()
raise NameError
print(5)
print(6)
Run Code Online (Sandbox Code Playgroud)
和输出...
Set jump to line 4 in tr.py
Run Code Online (Sandbox Code Playgroud)
问题很明显:一旦 sys.excepthook 被调用,外部作用域就消失了,所以任何时候都没有_trace机会在原始文件中运行!
如果我们假设有一个解决方案,然后再继续使用jump_to会怎么样?
import traceh
traceh.install()
import inspect
try:
raise NameError
print(1)
print(2)
print(3)
print(4)
print(5)
print(6)
except:
traceh.jump_to(10, inspect.currentframe())
Run Code Online (Sandbox Code Playgroud)
这对我们上次看到的问题没有影响,因为我们是jump_to在文件内部手动调用的。让我们来看看:
Set jump to line 10 in tr.py
Jumping to line 10 in tr.py
can't jump into the middle of a block
Run Code Online (Sandbox Code Playgroud)
该死的。
创意功劳主要归功于Richie Hindle的goto模块。