我可以 运行 没有装饰功能的装饰功能吗?

Can I run a decorated function without a decorator functionality?

如果我曾经对我的函数使用装饰器,我怎么能 运行 这个函数单独使用,而不嵌入装饰器功能?

例如我有一个函数printArg,它打印一个参数。为了某些可用性,我需要将它与 datetime.now()“混合”。为此,我写了一个装饰器 timeCalled。现在每次我调用 printArg 时也会调用一个装饰器。

有没有办法单独调用printArg,所以我不会重复自己写另一个没有装饰器功能的“printArg”(datetime.now())?

from datetime import datetime

def timeCalled(func):
    def wrapper(*args, **kwargs):
        print(f'{datetime.now()}: Function called {func.__name__}')
        result = func(*args, **kwargs)
        return result
    return wrapper

@timeCalled
def printArg(arg):
    print(f'Your arg is {arg}')

printArg('Mama')

装饰器只是被装饰函数的包装函数,语法:

@timeCalled
def printArg(arg):
    pass

相当于:

def printArg(arg):
    pass
printArg = timeCalled(printArg)

所以为了达到避免定义同一个函数两次的目标,只有一个被装饰,你可以定义一次函数,然后调用装饰器并传递给它的所述函数并将返回的函数对象分配给一个改为不同的名称:

def printArg(arg):
    print(f'Your arg is {name}')

timed_printArg = timeCalled(printArg)

这样就可以调用timed_printArg('Mama')定时调用printArg('Mama'),直接调用printArg('Mama')就可以了,不需要装饰器。

没有不依赖于实现细节的通用方法。在这个特殊情况中,由于func引用了wrapper中的原始函数并且在闭包中,你可以使用:

printArg.__closure__[0].cell_contents

找回它。

更一般地说,创建包装器时使用 functools.wraps 是一种很好的做法,这会使包装器函数“看起来像”原始函数。此外,它将原始功能添加到 __wrapped__ 属性,因此:

from datetime import datetime
from functools import wraps

def timeCalled(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print(f'{datetime.now()}: Function called {func.__name__}')
        result = func(*args, **kwargs)
        return result
    return wrapper

@timeCalled
def printArg(arg):
    print(f'Your arg is {name}')

在这种情况下,您可以使用:

printArg.__wrapped__

为你的修饰函数起一个不同的名字。为此,不要使用 @ 符号,而是:

decorated_printArg = timeCalled(printArg)