Python 将函数中的特定字符串替换为另一个字符串的装饰器

Python 将函数中的特定字符串替换为另一个字符串的装饰器,python,decorator,Python,Decorator,有可能这样做吗 def my_func(): my_list = ['abc', 'def', 'ghi'] my_str = 'abc' 如果我将A传递给decorator->将函数中的'abc'替换为'xxx',则传递B->yyy @装饰师('abc') 我不知道这是否可能 如何处理此问题?Decorator无法更改函数内部的逻辑。您可以对参数执行操作,也可以执行返回的任何操作。在您的情况下,您可以使用后装饰程序装饰程序不能更改函数内部的逻辑。您可以对参数执行操作,也可以执

有可能这样做吗

def my_func():
    my_list = ['abc', 'def', 'ghi']
    my_str = 'abc'
如果我将A传递给decorator->将函数中的'abc'替换为'xxx',则传递B->yyy

@装饰师('abc')

我不知道这是否可能


如何处理此问题?

Decorator无法更改函数内部的逻辑。您可以对参数执行操作,也可以执行返回的任何操作。在您的情况下,您可以使用后装饰程序

装饰程序不能更改函数内部的逻辑。您可以对参数执行操作,也可以执行返回的任何操作。在您的情况下,您可以使用后装饰器,可以用装饰器替换函数的代码对象,从而替换其中的常量,但这不太可能是您真正想要使用的解决方案

这几乎在任何规模下都无法维护,因为您的大截面看起来像:

#注意,这是特定于python 3.x的
码型(
argcount,#整数
kwonlyargcount,#整数
nlocals,#整数
堆栈大小,#整数
标志,#整数
代码字符串,#字节
常量,#元组
名称,#元组
变量名,#元组
文件名,#字符串
名称,#字符串
firstlineno,#整数
lnotab,#字节
自由变量,#元组
cellvars,#tuple
)
在其中,您需要从原始代码对象复制副本,并根据您的意图修改它们


这类问题的更好解决方案是允许将字符串作为参数传递给函数。如果以后需要在不存在字符串的情况下调用函数,则可以使用分部(请参见)

可以使用装饰器替换函数的代码对象,从而替换其中的常量,但这不太可能是您真正想要使用的解决方案

这几乎在任何规模下都无法维护,因为您的大截面看起来像:

#注意,这是特定于python 3.x的
码型(
argcount,#整数
kwonlyargcount,#整数
nlocals,#整数
堆栈大小,#整数
标志,#整数
代码字符串,#字节
常量,#元组
名称,#元组
变量名,#元组
文件名,#字符串
名称,#字符串
firstlineno,#整数
lnotab,#字节
自由变量,#元组
cellvars,#tuple
)
在其中,您需要从原始代码对象复制副本,并根据您的意图修改它们


这类问题的更好解决方案是允许将字符串作为参数传递给函数。如果以后需要在不存在字符串的情况下调用该函数,则可以使用分部(请参见)

您可以使用使用
ast.NodeTransformer
的装饰程序修改具有目标值的任何字符串节点,并在函数的ast中指定替换项:

import ast
import inspect
from textwrap import dedent

class Replace(ast.NodeTransformer):
    def __init__(self, target, replacement):
        self.target = target
        self.replacement = replacement

    def visit_Str(self, node):
        if node.s == self.target:
            node.s = self.replacement
        return node

    # remove 'replace' from the function's decorator list to avoid re-decorating during exec
    def visit_FunctionDef(self, node):
        node.decorator_list = [
            decorator for decorator in node.decorator_list
            if not isinstance(decorator, ast.Call) or decorator.func.id != 'replace'
        ]
        self.generic_visit(node)
        return node

def replace(target, repl):
    def decorator(func):
        tree = Replace(target, repl).visit(ast.parse(dedent(inspect.getsource(func))))
        ast.fix_missing_locations(tree)
        scope = {}
        exec(compile(tree, inspect.getfile(func), "exec"), func.__globals__, scope)
        return scope[func.__name__]
    return decorator
以便:

@replace('abc', 'xxx')
def my_func():
    my_list = ['abc', 'def', 'ghi']
    my_str = 'abc'
    print(my_list, my_str)

my_func()
产出:

['xxx', 'def', 'ghi'] xxx

演示:

您可以使用使用
ast.NodeTransformer
的装饰程序,使用函数的ast中给定的替换项修改具有目标值的任何字符串节点:

import ast
import inspect
from textwrap import dedent

class Replace(ast.NodeTransformer):
    def __init__(self, target, replacement):
        self.target = target
        self.replacement = replacement

    def visit_Str(self, node):
        if node.s == self.target:
            node.s = self.replacement
        return node

    # remove 'replace' from the function's decorator list to avoid re-decorating during exec
    def visit_FunctionDef(self, node):
        node.decorator_list = [
            decorator for decorator in node.decorator_list
            if not isinstance(decorator, ast.Call) or decorator.func.id != 'replace'
        ]
        self.generic_visit(node)
        return node

def replace(target, repl):
    def decorator(func):
        tree = Replace(target, repl).visit(ast.parse(dedent(inspect.getsource(func))))
        ast.fix_missing_locations(tree)
        scope = {}
        exec(compile(tree, inspect.getfile(func), "exec"), func.__globals__, scope)
        return scope[func.__name__]
    return decorator
以便:

@replace('abc', 'xxx')
def my_func():
    my_list = ['abc', 'def', 'ghi']
    my_str = 'abc'
    print(my_list, my_str)

my_func()
产出:

['xxx', 'def', 'ghi'] xxx

演示:

对不起,我不明白你说的“后装饰师”是什么意思。你能解释一下吗?对不起,我不明白你说的“后装潢师”是什么意思。你能解释一下吗?谢谢你的建议和解释!谢谢你的建议和解释!