python装饰器如何更改装饰函数中的调用?

2024-05-06 02:54:36 发布

您现在位置:Python中文网/ 问答频道 /正文

我不知道怎么做,坦白说,我不知道这是否可能。你知道吗

我想写一个修改函数调用方式的decorator。通过示例代码最容易看到:

def my_print(*args, **kwargs):
    print(args[0].upper())

@reroute_decorator('print', my_print)
def my_func():
    print('normally this print function is just a print function...')
    print('but since my_func is decorated with a special reroute_decorator...')
    print('it is replaced with a different function, and its args sent there.')

my_func()
# NORMALLY THIS PRINT FUNCTION IS JUST A PRINT FUNCTION...
# BUT SINCE MY_FUNC IS DECORATED WITH A SPECIAL REROUTE_DECORATOR...
# IT IS REPLACED WITH A DIFFERENT FUNCTION, AND ITS ARGS SENT THERE.

在python中,具有这种功能的装饰器是可能的吗?你知道吗

现在,我真的不需要这个,如果它太复杂,我只是不知道如何用一个简单的方法来做。你知道吗

这种问题是微不足道的吗?还是真的很复杂?你知道吗


Tags: ismydefwithargsfunctiondecoratorfunc
2条回答

为了详细说明@Dan D.'s answer,您需要创建一个新的函数对象来替换原来的函数对象,如下所示:

from types import FunctionType

def reroute_decorator(**kwargs):
    def actual_decorator(func):
        globals = func.__globals__.copy()
        globals.update(kwargs)
        new_func = FunctionType(
            func.__code__, globals, name=func.__name__,
            argdefs=func.__defaults__, closure=func.__closure__)
        new_func.__dict__.update(func.__dict__)
        return new_func
    return actual_decorator

这里唯一需要注意的是,更新后的函数对象是only对象,它将看到您传入的kwargs,因为它们将被欺骗成全局变量。另外,在调用decorator函数之后对模块所做的任何修改对decorator函数都是不可见的,但这应该不是问题。您可以再深入一层,创建一个代理字典,它允许您正常地与原始的进行交互,但您显式定义的键除外,如print,但这有点超出了范围。你知道吗

我已经将您的print实现更新为更一般的实现,并使decorator函数的输入更加pythonic(不太复杂):

def my_print(*args, **kwargs):
    print(*(str(x).upper() for x in args), **kwargs)

@reroute_decorator(print=my_print)
def my_func():
    print('normally this print function is just a print function...')
    print('but since my_func is decorated with a special reroute_decorator...')
    print('it is replaced with a different function, and its args sent there.')

结果是:

>>> my_func()
NORMALLY THIS PRINT FUNCTION IS JUST A PRINT FUNCTION...
BUT SINCE MY_FUNC IS DECORATED WITH A SPECIAL REROUTE_DECORATOR...
IT IS REPLACED WITH A DIFFERENT FUNCTION, AND ITS ARGS SENT THERE.

您可以使用更新的globals字典创建一个新函数,以使该函数看起来全局已绑定到所需的值。你知道吗

请注意,这比实际的动态范围弱,因为该函数调用的任何函数都将看到原始绑定,而不是修改的绑定。你知道吗

参见How does Python's types.FunctionType create dynamic Functions?中引用的namespaced_function

相关问题 更多 >