我可以在没有装饰器功能的情况下运行装饰函数吗?

问题描述 投票:0回答:3

如果我曾经在我的函数中使用了装饰器,我如何单独运行这个函数,而不嵌入装饰器功能中?

例如,我有一个函数

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')
python python-3.x decorator python-decorators
3个回答
3
投票

没有不依赖于实现细节的通用方法。在这个特殊情况中,由于

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(name):
    print(f'Your arg is {name=}.')

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

printArg.__wrapped__

1
投票

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

@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')
来完成,不需要装饰器的参与。


1
投票

给你的装饰函数起一个不同的名字。为此,不要使用

@
符号,而是使用:

decorated_printArg = timeCalled(printArg)
© www.soinside.com 2019 - 2024. All rights reserved.