1.装饰器定义和原则

定义:装饰器本质是一个函数,(装饰其它函数)就是为其它函数添加附加功能。

原则:不能修改被装饰函数的源代码;不能修改被装饰函数的调用方式。


2.实现装饰器知识储备

1.函数即变量

2.高阶函数

a.把一个函数名当做实参传给另一个函数--》可以实现不修改被装饰函数的源代码,为其它函数添加附加功能

import time
def test1():
    time.sleep(3)
    print("this is test1")

def test2(func):
    start_time = time.time()
    func()
    stop_time = time.time()
    print("this func run time is %s"%(stop_time-start_time))
test2(test1)

b.返回值中包含函数名-->可以实现不修改被装饰函数的调用方式

def test3():
    print("this is test3")

def test4(func):
    print("附加功能")
    return func
test3 = test4(test3)
test3()

注:调用函数的时候不加括号表示调用该函数内存地址如:print(test3)--><function test3 at 0x003E7660>,加括号表示执行该函数

3.嵌套函数 ,在一个函数里再次声明一个函数

def test5():
    print("this is test5")
    def test6():            #类似于局部变量,只能在局部调用
        print("this is test6")
    test6()
test5()

4.高阶函数+嵌套函数--》装饰器

a.装饰器举例1

import time
    #装饰器:增加计算函数运行时间的功能
def timer(func):
    def deco(*args,**kwargs):                     #在装饰器中增加*args,**kwargs之后,无论原函数参数的个数是多少,都可以适应
        start_time = time.time()
        res = func(*args,**kwargs)
        stop_time = time.time()
        print("this func run time is %s"%(stop_time-start_time))
        return res                               #在装饰器中增加return res之后,可以返回原函数中的返回值
    return deco
#下面的1,2也就是装饰器执行的过程

    #原函数
@timer                          #1、 @timer 实际上是在执行“test1 = timer(test1)”-->将原test1 内存地址传给func,然后直接将deco的内存地址返回到test1
def test1():
    time.sleep(3)
    print("this is test1")
#test1 = timer(test1)
test1()                          #2、这时test1()相当于直接调用deco(*args,**kwargs),而deco里的func还是指向的原test1的内存地址

@timer
def test2(name):
    time.sleep(1)
    print("this is %s"%(name))
test2("fengxiaoli")

@timer
def test3(name):
    time.sleep(2)
    print("this is %s"%(name))
    return "test3 res"
print(test3("cx"))      #先执行test3(cx),再打印test3的返回结果

b.装饰器举例2

#给网页增加一个验证的功能,并且home页面用本地验证,bbs页面用ldap验证
user = "fengxiaoli"
passwd = "123456"
def auth(auth_type):
    def out_wrapper(func):
        def wrapper(*args,**kwargs):
            if auth_type == "local":
                user_name = input("请输入用户名:").strip()
                password = input("请输入密码:").strip()
                if user_name == user and password == passwd:
                    res = func(*args,**kwargs)
                    print("welcome to home!")
                    return res
                else:
                    print("用户名或密码错误")
            else:
                print("ldap login")
        return wrapper
    return out_wrapper


#原函数
def index():
    print("this is index")

@auth(auth_type="local")                     #相对于装饰器1中的例子,这里调用装饰器的时候使用了参数,在1中装饰器不变得情况下直接在外在嵌套了一层函数,最外层函数接收的就是装饰器中的参数
def home():
    print("this is home page")
home()

@auth(auth_type="ldap")
def bbs():
    print("this is bbs page")

bbs()