为了简单起见,我将我的问题缩小到以下几个方面:
我有一个main函数,它执行一系列函数。从第一个函数manipulate()开始,我希望能够阻止test()通过sys.exit()退出程序。我还需要能够使print("Silence me")静默,这意味着这不应该出现在我的程序的输出中。最后,我的程序仍然需要能够从test()函数输出print("You need to hear this")。
def main():
manipulate()
test()def manipulate():
print("Silence me")
sys.exit()
print("You need to hear this")如果我只能更改manipulate()函数中的代码,我如何实现这一点呢?
我尝试过使用inspect模块,但我想我可能遗漏了一些东西。我不确定为test()解析代码并通过exec()运行解析后的代码是否是实现这一目标的正确方法。
def manipulate():
def filter_exc(func):
src = inspect.getsource(func)
lines = src.split('\n')
out = lines[0] + "\n"
for line in lines[1:]:
m = re.match('(\s*)(.*)', line)
lead, text = m.groups()
if 'sys.exit()' in line:
continue
if 'Silence Me' in line:
continue
out += " " + text + '\n'
return out
exec(filter_exc(game_on))发布于 2019-06-30 05:05:03
在这个简单的例子中,我只是"monkeypatch“受影响的功能:
from contextlib import contextmanager
import sys
def test():
print("Silence me")
sys.exit()
print("You need to hear this")
@contextmanager
def manipulate():
global print
try:
_sys_exit_backup, sys.exit = sys.exit, lambda: None
i = iter([lambda *args:None, print])
_print_backup, print = print, lambda *args: next(i)(*args)
yield
finally:
sys.exit = _sys_exit_backup
print = _print_backup
def main():
with manipulate():
test()
main()打印:
You need to hear this发布于 2019-06-30 05:10:23
首先,你需要知道你正在做的事情是不好的。设计的编程语言执行源代码,而不是限制执行。编辑活动字节码是邪恶的,并且会产生无法调试的错误。
抛开免责声明不谈,您可以通过使用标准库中的patch替换exit和print的标准实现来更干净地实现此效果,但您需要执行如下内容
from unittest.mock import patch
import sys
def my_print(*args, **kwargs):
# do whatever
return
def my_exit(*args, **kwargs):
# do whatever
return
def perform_patch():
patchers = [
patch('__main__.print', my_print),
patch('sys.exit', my_exit)
]
for patcher in patchers:
patcher.start()
return patchers
def perform_unpatch(patchers):
for patcher in patchers:
patcher.stop()
def manipulate():
print("hello")
sys.exit(1)
def main():
patchers = perform_patch()
manipulate()
perform_unpatch(patchers)
print("I'm done!")
if __name__ == '__main__':
main()脚本只输出“我完成了!”。
在您调用patcher.stop()之前,exit和print将一直处于修补状态。patch可以在with块中使用,所以如果您可以将manipulate()调用放在with语句中,那么它可以更清晰地完成。
另一种方法是获取源代码,并使用ast模块动态重写它。这是一个talk about ASTs。
最后,您可以直接使用字节码执行某些操作,这是一个talk exploring that。
最后,我强烈建议您使用任何其他可能的方式来编辑源代码。如果它是一个库,那么如果你直接派生它并直接编辑源代码会更好。
https://stackoverflow.com/questions/56820600
复制相似问题