为什么我们需要装饰器中的包装器功能?

时间:2017-07-26 19:12:55

标签: 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!")

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

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")

两个装饰器都会一样。使用"包装"有什么好处?装饰里面的功能。我没有达到目的。

3 个答案:

答案 0 :(得分:3)

具有包装函数的目的是函数装饰器接收要装饰的函数对象,并且必须返回装饰函数。

您的第二版my_decorator没有明确的return语句,因此返回None。通过my_decorator装饰器语法

调用@
before some_function() is called.
some fun
after some_function() is called.

打印,然后None被分配到名称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)

答案 1 :(得分:1)

Python中的装饰器是可调用对象,在最简单的情况下,函数采用一个参数,即某个函数或类。装饰器应该再次返回它所采用的相同类型(所以如果它需要函数它应该返回函数)。这一点是在调用装饰器的时候。

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

如果解释器在装饰器上遇到它需要装饰函数,则调用装饰器并用装饰器返回的值替换装饰函数。

假设你有这段代码:

@my_decorator
def my_function()
  print("My_function")

这相当于这个电话:

def my_function()
    print("My_function")    

my_function = my_decorator(my_function)

如果装饰者会像这样

def my_decorator(func):
    print("decorated)
    return 42

然后my_function甚至不是一个整数的函数(你可以尝试print(my_function)

所以当你将装饰器定义为

def my_decorator2(some_fun):
    print("before")
    some_fun()
    print("after")

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

@my_decorator2
def decorated():
  print("inside")

打印

before
inside
after

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

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

答案 2 :(得分:0)

  

它已经解释了为什么我出于好奇而使用包装器功能   举例说明了如果不需要包装函数怎么办。

类型1

返回一个小函数,该函数返回Nonepass

def decorator_func(to_be_decorated_function):
    print("Logging IN: Currrently  in function")
    to_be_decorated_function()
    print("Logging OUT: Currrently  in function")

    def a(): None  # or def a(): pass

    return (a)

@decorator_func
def to_be_decorated_function():
    print('October 16, 2000')

to_be_decorated_function()
# equivalent to 
#to_be_decorated_function = decorator_func(to_be_decorated_function)

类型2

这只是撕裂了装饰器的用法,并且做了一些微调。如果我们不返回,那根本就不使用可调用对象。

def decorator_func(to_be_decorated_function):
    print("Logging IN: Currrently  in function")
    to_be_decorated_function()
    print("Logging OUT: Currrently  in function")

@decorator_func
def to_be_decorated_function():
    print('October 16, 2000')

to_be_decorated_function  # notice I'm just using the object and not callable function
# equivalent to
#decorator_func(to_be_decorated_function)

两种类型的输出

Logging IN: Currrently  in function
October 16, 2000
Logging OUT: Currrently  in function