为什么在装饰器中需要包装器功能?

Ank*_*jan 8 python python-3.x python-decorators

如果我创建如下的装饰器:

def my_decorator(some_fun):
    def wrapper():
        print("before some_function() is called.")
        some_fun()
        print("after some_function() is called.")
    return wrapper

@my_decorator
def just_some_function():
    print("Wheee!")
Run Code Online (Sandbox Code Playgroud)

另一个装饰器可以定义为:

def my_decorator(some_fun):
    print("before some_function() is called.")
    some_fun()
    print("after some_function() is called.")

@my_decorator
def just_some_fun():
    print("some fun")
Run Code Online (Sandbox Code Playgroud)

两个装饰器将工作相同。在装饰器中使用“包装器”功能有什么好处。我没有达到目的。

PM *_*ing 11

拥有包装函数的目的是函数装饰器接收一个函数对象进行装饰,并且它必须返回被装饰的函数。

你的第二个版本my_decorator没有明确的return声明,所以它返回None. 何时my_decorator通过@装饰器语法 调用

before some_function() is called.
some fun
after some_function() is called.
Run Code Online (Sandbox Code Playgroud)

被打印,然后None被分配给 name just_some_fun。因此,如果您添加print(just_some_fun)到该代码的末尾,它将打印None.

如果我们去掉@语法糖并使用正常的函数调用语法重新编写代码,可能会更容易理解发生了什么:

def my_decorator(some_fun):
    print("before some_function() is called.")
    some_fun()
    print("after some_function() is called.")

def just_some_fun():
    print("some fun")

just_some_fun = my_decorator(just_some_fun)
Run Code Online (Sandbox Code Playgroud)


Qee*_*eek 9

Python 中的装饰器是可调用对象,在最简单的情况下,它是带有一个参数的函数,该参数是某个函数或类。装饰器应该再次返回它所采用的相同类型(所以如果它采用函数,它应该返回函数)。关键在于调用装饰器的时间。

当您导入 Python 文件或直接运行它时,Python 解释器会遍历内容并收集有关定义了哪些类和函数的信息,如果遇到某些代码(不是声明),它将执行它。

如果解释器遇到装饰器,它接受装饰的函数,调用装饰器并用装饰器的返回值替换装饰的函数。

假设您有以下代码:

@my_decorator
def my_function()
  print("My_function")
Run Code Online (Sandbox Code Playgroud)

它相当于这个调用:

def my_function()
    print("My_function")    

my_function = my_decorator(my_function)
Run Code Online (Sandbox Code Playgroud)

如果装饰者是这样的

def my_decorator(func):
    print("decorated)
    return 42
Run Code Online (Sandbox Code Playgroud)

那么my_function它甚至不是一个函数而是一个整数(你可以试试print(my_function)

所以当你将装饰器定义为

def my_decorator2(some_fun):
    print("before")
    some_fun()
    print("after")
Run Code Online (Sandbox Code Playgroud)

然后这个装饰器什么都不返回(在python中它意味着它返回None)。

@my_decorator2
def decorated():
  print("inside")
Run Code Online (Sandbox Code Playgroud)

印刷

before
inside
after
Run Code Online (Sandbox Code Playgroud)

但调用decorated()会引发异常,'NoneType' object is not callable因为decorated被替换为None.

你应该总是创建装饰器,它返回一些有用的东西,比如函数或类(通常是里面的“包装”函数)。有时从装饰器返回其他东西然后返回函数/类可能很有用,但它通常会混淆您的代码并将其转换为完全不可维护的东西。