装饰器详解

一、闭包

了解装饰器前,首先要了解,什么是闭包。

闭包就是在一个函数中再定义一个函数,内部函数需要引用外部函数的参数,且外部函数的返回值是内部函数。

def outside(x):
    def inside(y):
        return x + y
    return inside

print(outside(1)(2))
-----------------------------
>>>3

如代码所示,outside返回一个内部函数inside,且inside函数引用了outside函数中的变量x,这就是闭包。

因为outside函数返回的是inside函数,所以outside(1)就相当于

def inside(y):
    return 1 + y

outside(1)(2)相当于
def inside(2):
    return 1 + 2

 

二、装饰器

1、装饰器

装饰器就是闭包的一种应用。他的作用就是在不改变函数代码的基础上上,为函数扩展一些新功能。

当一个函数需要添加这个新功能时,只需要在函数上方添加@name即可。

import time

def needTime(func):
    def inner():
        start_time = time.time()
        func()
        end_time = time.time()
        print(f"当前函数耗时:{end_time - start_time}s")

    return inner

@needTime
def demo():
    time.sleep(1)
    print("hello")

demo()
-------------------------------

hello
当前函数耗时:1.0144729614257812s

如上代码所示,不需要修改hello()函数,就能添加计算函数耗时的功能

 

2、带参数的装饰器

def logging(level):
    def outwrapper(func):
        def wrapper(*args, **kwargs):
            print("[{0}]: enter {1}()".format(level, func.__name__))
            return func(*args, **kwargs)
        return wrapper
    return outwrapper

@logging(level="INFO")
def hello(a, b, c):
    print(a, b, c)

hello("hello,","good","morning")
-----------------------------
>>>[INFO]: enter hello()
>>>hello, good morning

我们可以这么理解上方代码:

@logging(level="INFO")可以看作为:hello = logging("INFO")(hello)

logging函数的返回值为outwrapper函数,则:

hello = outwrapper(hello)

而outwrapper返回的就是wrapper,所以:

hello = wrapper(*args,**kwargs)

 

3、类装饰器

类装饰器的本质就是通过类方法中的call魔术方法来实现

(1)不带参数的类装饰器

class logging(object):
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        print("[DEBUG]: enter {}()".format(self.func.__name__))
        return self.func(*args, **kwargs)

@logging
def hello(a, b, c):
    print(a, b, c)

hello("hello,","good","morning")
-----------------------------
>>>[DEBUG]: enter hello()
>>>hello, good morning

(2)带参数的类装饰器

class logging(object):
    def __init__(self, level):
        self.level = level

    def __call__(self, func):
        def wrapper(*args, **kwargs):
            print("[{0}]: enter {1}()".format(self.level, func.__name__))
            return func(*args, **kwargs)
        return wrapper

@logging(level="TEST")
def hello(a, b, c):
    print(a, b, c)

hello("hello,","good","morning")
-----------------------------
>>>[TEST]: enter hello()
>>>hello, good morning

 

参考原文:https://zhuanlan.zhihu.com/p/87353829

posted @ 2022-09-22 15:28  只为。  阅读(78)  评论(0)    收藏  举报