装饰器的概念

装饰器是程序开发过程中经常会用到的一个功能,用好装饰器,开发效率就会如虎添翼

装饰器的功能

引入日志,函数执行时间统计,执行前函数预备处理,执行后函数清理功能,权限校验等功能

学装饰器的前提

要想学好装饰器,需要了解什么是闭包

闭包的概念

在函数内部再定义一个函数,并且这个函数用到了外面函数的变量,那么将这个函数以及用到的一些变量称之为闭包

闭包的定义

def line_conf(a, b):
    def line(x):
        return a*x + b
    return line

line1 = line_conf(1, 1)
print(line1(5))

当函数执行line_conf的时候,返回的是一个内层函数的地址.我们用line1接收line_conf返回的值,然后我们调用line1()函数,就等同于调用内层的line()函数,这就是一个闭包

装饰器的执行过程

装饰器的执行原理

# 这是一个闭包
def w1(fun):
    def inner():
        fun() # 指向了f1函数
    return inner
# 这是一个普通函数
def f1():
    print("这是f1函数")
# 将w1的返回值给f1
f1 = w1(f1)
# 此函数实际上执行的是inner()函数
f1()

装饰器的定义

def w1(fun):
        def inner():
            fun() # 指向了f1函数
        return inner
@w1
def f1():
    print("这是f1函数")
# 实际指向了inner函数
f1()

同一个函数被两个装饰器装饰时

如果一个函数被两个装饰器函数装饰,执行过程是从上至下,但实际装饰过程是从下至上
# 定义函数,完成包裹数据
def makeBold(fun):
print(“正在装饰1”)
def wrapped():
print(“—1—”)
return “” + fun() + “
return wrapped

#定义函数,完成包裹数据
def makeItalic(fun):
    print("正在装饰2")
    def wrapped():
        print("---2---")
        return "<i>" + fun() + "</i>"
    return wrapped

# 进行装饰
@makeBold    # 相当于text3 = makeBold(text2)
@makeItalic  # 相当于text2 = nameItalic(text3)
def text3():
    print("---3---")
    return "hello world!"

# 打印结果
ret = text3()
print(ret)
结果为
正在装饰2
正在装饰1
---1---
---2---
---3---

装饰器的分类

装饰无参数,无返回值的函数

def fun(functionName):
    def fun_in():
        print("这是fun_in函数")
        functionName()
    return fun_in
@fun
def f1():
    print("这是f1函数!")
f1()

装饰有参数,无返回值的函数

def fun(functionName):
    def fun_in(*args, **kwargs):
        print("这是fun_in函数")
        functionName(*args, **kwargs))
    return fun_in
@fun
def f1(a, b):
    print("%s%s" %(a, b))
f1(1, 2)

装饰无参数,有返回值的函数

def fun(functionName):
    def fun_in():
        print("这是fun_in函数")
        ret = functionName()
    return fun_in
@fun
def f1():
    return "hello python!"
ret = f1() # 指向fun_in函数
print(ret)

装饰有参数,有返回值的函数(通用装饰器)

def fun(functionName):
    def fun_in(*args, **kwargs):
        print("这是fun_in函数")
        ret = functionName(*args, **kwargs))
    return fun_in
@fun
def f1(a, b):
    return a + b
ret = f1(1, 2)
print(ret)

带参数的装饰器
带参数的装饰器的作用:能够在运行的过程中,起到不同的作用

# 需要一个三层函数来实现
def fun_arg(arg):
    def fun(functionName):
        def fun_in():
            print("装饰器的参数是:%s" %(arg))
            functionName()
        return fun_in
return fun

@fun_arg("ha ha ha") # 装饰器带参数
def text():
    print("---text---")
text()

类装饰器

call 魔法方法

class Test(object):
    # __call__可以直接调用
    def __call__(self):
        print("---test---")
t = Test()
t()

结果为

---test---

类装饰器的用法

class Test(object):
    def __init__(self, func):
        print("初始化")
        print("func name is %s" %func.__name__)
        self.__func = func
    def __call__(self):
        print("装饰器的功能")
        self.__func()
@Test  # 相当于执行了test = Test(test)
def test():
    print("---test--") # 敲完回车,自动开始装饰,出现以下信息
---初始化---
func name is test

结果为:

装饰器的功能
---test---