为什么在装饰器或嵌套函数中返回函数时不调用函数

时间:2020-09-18 03:47:49

标签: python python-3.x function return python-decorators

当我们在函数内部编写函数时,为什么不调用它呢?回报如何称呼它?

def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
return wrapper

为什么用return wrapper代替return wrapper()?以及包装器必须接受参数时我们该怎么做?

2 个答案:

答案 0 :(得分:2)

函数可以像Python中的值一样对待

def foo():
    print("Hello World!")
x = foo
x()

是有效的Python,将打印出Hello World!

扩展这个想法...如果我们想在调用函数之前做点什么?好吧,我们可以这样做:

def foo():
    print("Hello World!")
def do_something_before():
    print("something before")
    foo()
x = do_something_before
x()

但是我们已经将自己锁定为只能使用foo函数。如果我们想为barfoobar或任意数量的功能做“事前准备”怎么办?

我们将其参数化!并且由于我们要在“正常”函数上添加额外的位,即装饰它,所以我们将此新函数称为装饰器。

def foo():
    print("Hello World!")

def do_something_before(func): # the decorating function
    def wrap():
        print("something before")
        func()
    return wrap

x = do_something_before(foo)
x()

然后,Python允许我们在任何需要的地方使用语法糖来执行此操作:

def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

@my_decorator
def foo():
    print("Hello World!")

装饰器必须接受一个函数,然后允许再次调用它,因此,我们将直接返回带有foo的函数,而不是直接调用foo,以便稍后在调用foo时调用。我们实际上正在调用包装器,由foo返回。如果在装饰器中调用wrapper,则将返回wrapper的结果,而不是wrapper本身。这意味着我们以后不能调用foo(),因为实际上没有要调用的函数。 我们可以添加这样的参数:

def my_decorator(func):
    def wrapper(*args):
        print("Something is happening before the function is called.")
        func(*args)
        print("Something is happening after the function is called.")
    return wrapper

含义my_decorator现在可以修饰任何功能。我们还可以指定特定数量的参数。

答案 1 :(得分:1)

装饰器用于将功能替换为其他功能,通常是通过某种方式修改原始功能的行为。因此,装饰器必须返回一个应调用的函数,而不是原始函数。

如果返回了wrapper(),则只需调用一次新的wrapper函数并返回结果。但是您真正需要做的是将func替换为wrapper,这样,每当有人呼叫func时,他们实际上会呼叫wrapper,然后呼叫{ {1}}。因此func本身必须返回my_decorator,而不是wrapper的输出。然后,当您使用wrapper()作为修饰符时,Python每次都会自动调用my_decorator而不是原始函数。

wrapper函数应始终使用与wrapper相同的参数。因此,如果需要参数,只需使用与func行中的func相同的参数进行定义即可。