有可能这样做吗?
def my_func():
my_list = ['abc', 'def', 'ghi']
my_str = 'abc'如果我将A传递给装饰器,并将函数中的'abc‘替换为'xxx’,则传递B -> yyy
@装饰器(‘abc’)
def my_func():
my_list = ['xxx', 'def', 'ghi']
my_str = 'xxx'我不知道这是不是可能。
我该怎么做呢?
发布于 2019-10-23 12:31:01
您可以使用一个装饰器,该装饰器使用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发布于 2019-10-23 12:29:07
可以用装饰器替换函数的代码对象,从而替换其中的常量,但这不太可能是您真正想要的解决方案。
这几乎在任何规模下都是不可维护的,因为你会有很大的部分看起来像这样:
# Note, this is python 3.x specific
CodeType(
argcount, # integer
kwonlyargcount, # integer
nlocals, # integer
stacksize, # integer
flags, # integer
codestring, # bytes
consts, # tuple
names, # tuple
varnames, # tuple
filename, # string
name, # string
firstlineno, # integer
lnotab, # bytes
freevars, # tuple
cellvars, # tuple
)其中您需要从原始代码对象复制,并根据您的意图对其进行修改。
对于这类问题,更好的解决方案是允许将字符串作为参数传递给函数。如果您需要函数稍后在没有字符串的情况下可调用,则可以使用partial (参见functools.partial)
发布于 2019-10-23 12:18:05
装饰器不能改变你函数内部的逻辑。你既可以对参数进行操作,也可以对返回的内容进行操作。在你的例子中,你可以使用post修饰器
https://stackoverflow.com/questions/58515362
复制相似问题