为简单起见,我将问题缩小到以下范围:
我有一个执行一系列功能的主要功能。从第一个功能manipulate()
开始,我希望能够防止test()
用sys.exit()
退出程序。我还需要能够使print("Silence me")
保持沉默,这意味着它不应显示在程序的输出中。最后,我的程序仍然需要能够从print("You need to hear this")
函数中输出test()
。
def main():
manipulate()
test()
def manipulate():
print("Silence me")
sys.exit()
print("You need to hear this")
如果我只能在handler()函数中更改代码,该如何实现?
我已经尝试研究使用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))
答案 0 :(得分:0)
在这个简单的示例中,我只是“ 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
答案 1 :(得分:0)
首先,您需要知道自己在做什么是不好的。设计的编程语言会执行源代码,而不是限制执行。编辑实时字节码是邪恶的,并且会产生不可辩驳的错误。
抛弃免责声明,您可以通过使用标准库中的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()
脚本仅输出“我完成了!”。
exit
和print
将保持修补状态,直到您致电patcher.stop()
。 patch
可以在with
块中使用,因此,如果可以将manipulate()
调用放在with
语句中,则可以更干净。
另一种方法是获取源代码并使用ast模块动态地重写它。这是talk about ASTs。
最后,您可以直接使用字节码执行操作,这是talk exploring that。
最后,我强烈建议您使用任何其他可能的方式来编辑源。如果它是一个库,那么如果您将它派生并直接编辑源代码,那就更好了。