首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用Inspect模块执行特定代码

使用Inspect模块执行特定代码
EN

Stack Overflow用户
提问于 2019-06-30 04:16:17
回答 2查看 40关注 0票数 1

为了简单起见,我将我的问题缩小到以下几个方面:

我有一个main函数,它执行一系列函数。从第一个函数manipulate()开始,我希望能够阻止test()通过sys.exit()退出程序。我还需要能够使print("Silence me")静默,这意味着这不应该出现在我的程序的输出中。最后,我的程序仍然需要能够从test()函数输出print("You need to hear this")

代码语言:javascript
复制
def main():
    manipulate()
    test()
代码语言:javascript
复制
def manipulate():

    print("Silence me")
    sys.exit()
    print("You need to hear this")

如果我只能更改manipulate()函数中的代码,我如何实现这一点呢?

我尝试过使用inspect模块,但我想我可能遗漏了一些东西。我不确定为test()解析代码并通过exec()运行解析后的代码是否是实现这一目标的正确方法。

代码语言:javascript
复制
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))
EN

回答 2

Stack Overflow用户

发布于 2019-06-30 05:05:03

在这个简单的例子中,我只是"monkeypatch“受影响的功能:

代码语言:javascript
复制
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()

打印:

代码语言:javascript
复制
You need to hear this
票数 0
EN

Stack Overflow用户

发布于 2019-06-30 05:10:23

首先,你需要知道你正在做的事情是不好的。设计的编程语言执行源代码,而不是限制执行。编辑活动字节码是邪恶的,并且会产生无法调试的错误。

抛开免责声明不谈,您可以通过使用标准库中的patch替换exitprint的标准实现来更干净地实现此效果,但您需要执行如下内容

代码语言:javascript
复制
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()之前,exitprint将一直处于修补状态。patch可以在with块中使用,所以如果您可以将manipulate()调用放在with语句中,那么它可以更清晰地完成。

另一种方法是获取源代码,并使用ast模块动态重写它。这是一个talk about ASTs

最后,您可以直接使用字节码执行某些操作,这是一个talk exploring that

最后,我强烈建议您使用任何其他可能的方式来编辑源代码。如果它是一个库,那么如果你直接派生它并直接编辑源代码会更好。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56820600

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档