是否可以使用其他功能更改功能代码,并通过eval执行?

问题描述 投票:-1回答:1

我正在尝试应用装饰器来更改功能代码,然后使用更改后的代码执行此功能。

下面是具有示例功能的temp模块。如果将[*args, **kwargs, 123]应用于此函数,我只是希望该函数返回[*args, **kwargs]而不是some_decorator

from dill.source import getsource

def some_decorator(method):
    def wrapper(*args, **kwargs):
        source_code = getsource(method)
        code_starts_at = source_code.find('):') + 2
        head = source_code[:code_starts_at]
        body = source_code[code_starts_at:]

        lines = body.split('\n')
        return_line = [i for i in lines if 'return' in i][0]
        old_expr = return_line.replace('    return ', '')
        new_expr = old_expr.replace(']', ', 123]')

        new_expr = head + '\n' + '    return ' + new_expr
        new_expr = new_expr + '\n' + method.__name__ + '(*args, **kwargs)'

        return eval(new_expr)
    return wrapper

@some_decorator
def example_func(*args, **kwargs):
    return [*args, **kwargs]

更多说明:我正在重写原始功能

def example_func(*args, **kwargs):
    return [*args, **kwargs]

to

def example_func(*args, **kwargs):
    return [*args, **kwargs, 123]
example_func(*args, **kwargs)

希望eval能够编译并运行此修改的函数。

当我尝试按照下面的代码运行它时,它返回语法错误。

from temp import example_func
example_func(5)

我知道eval可以解决这个问题:

[*args, **kwargs, 123]

但仅当已经声明argskwargs时。我希望在执行example_func(args, kwargs)时从example_func中读取它们。

我想只是将修改后的功能代码写入文件中

def example_func(*args, **kwargs):
    return [*args, **kwargs, 123]

并使some_decorator执行修改后的代码而不是原始代码的功能,就可以了。但是,理想情况下,我将跳过创建任何中间文件的过程。

是否可以实现?

python eval decorator
1个回答
1
投票

虽然从技术上讲,您几乎可以使用Python中的函数和装饰器来做任何事情,但您[[不应。

在这种情况下,向返回列表的函数添加额外的值很简单:

def some_decorator(method): def wrapper(*args, **kwargs): result = method(*args, **kwargs) return result + [123] return wrapper

这不需要任何功能代码重写。如果您要做的只是更改函数的输入或输出,请

只需更改输入或输出

,并保留函数本身。请注意,eval()

不能

会更改您的功能,因为eval()严格限于表达式。创建函数的def语法为statement。从根本上讲,语句可以包含表达式和其他语句(例如if <test_expression>: <body of statements>),但表达式不能包含语句。要将文本作为任意Python代码执行,您必须改用exec() function接下来,用于重建Python代码的文本处理非常低效且容易出错。您最好让Python将源代码编译为

抽象语法树

(通过exec()),然后在该树上工作。定义明确的对象的有向图比文本容易操作(在使用多少空白等方面更灵活)。有关重写Python代码的项目的真实示例,请查看ast module。他们使用模块导入钩子来执行此操作,但是只要功能可使用源代码,您也可以使用装饰器来执行此操作。

使用ast模块来更改how pytest rewrites the assert statement to add extra context语句中的列表:

assert

请注意,此

不需要包装函数

。您无需在每次尝试调用函数时都进行重新处理,装饰器只需执行一次即可返回该结果。
© www.soinside.com 2019 - 2024. All rights reserved.