Python篇-装饰器

一 : 装饰器demo及分析

我们为函数添加一段附加功能,并且秉承着

  1. 不修改被修饰函数的源代码
  2. 不修改被修饰函数的调用方式

这种非常炫酷的添加附加功能的方式叫做装饰器

import time

#时间装饰器
def timmer(func):
    def wapper(*args,**kwargs):
        start_time = time.time()
        res = func(*args,**kwargs)
        stop_time = time.time()
        print('函数时间是 : %s' % (stop_time - start_time))
        return  res
    return wapper

@timmer
def cal(l):
    res = 0
    for i in l:
        time.sleep(0.1)
        res += i
    return res
print(cal(range(20)))
函数时间是 : 2.0555498600006104
190

二 : 闭包

闭包说白了就是函数嵌套的另一种叫法,每层包都有自己的局部变量, 函数也要看成一种变量存放在自己那层的包中,每一层的嵌套 ,那一层就是一个包.

def first(name):
    def second():
        name = "222"
        print(name)
        def third():
            name = "333"
            print("哈哈哈"+name)
        third()
    print(name)
    second()
first('111')
111
222
哈哈哈333

三 : 装饰器推导

装饰器 = 高阶函数 + 函数嵌套 + 闭包

① : 雏形

虽然没有修改foo函数源代码,也没有修改foo函数调用方式,但是运行结果却多执行了一次

def foo():
    time.sleep(3)
    print('来自foo')

def timer(func):
    start_time = time.time()
    func()
    stop_time = time.time()
    print("运行时间为 : "+str(stop_time - start_time))
    return func

foo = timer(foo)
foo()
来自foo
运行时间为 : 3.002413034439087
来自foo
② : 闭包

利用闭包,(函数嵌套)将func函数传入内部执行,返回wrapper函数,赋值给test,再运行test()巧妙的解决了 步骤 ① 的问题

def timmer(func):
    def wrapper():
        start_time = time.time()
        func()#运行test
        stop_time = time.time()
        print("运行时间" + str(stop_time - start_time))
    return wrapper

def test():
    time.sleep(3)
    print("函数运行完毕")

 test = timmer(test) #返回是wrapper地址
 test() #执行的是wrapper()
③ : 语法糖

将②步骤,修改成语法糖的形式 ,@timmer 相当于test = timmer(test)

def timmer(func):
    def wrapper():
        start_time = time.time()
        func()#运行test
        stop_time = time.time()
        print("运行时间" + str(stop_time - start_time))
    return wrapper

@timmer #test = timmer(test)
def test():
    time.sleep(3)
    print("函数运行完毕")

#语法糖 @timer就相当于 test = timmer(test)
 test()
④ : 增加返回值

在③ 的基础上,添加了返回值.使得函数有返回值

def timmer(func):
    def wrapper():
        start_time = time.time()
        res = func()#运行test
        stop_time = time.time()
        print("运行时间" + str(stop_time - start_time))
        return res
    return wrapper

@timmer #test = timmer(test)
def test():
    time.sleep(3)
    print("函数运行完毕")
    return "我是test"

res = test()
print(res)
⑤ : 增加参数

在④的基础上增加参数,使得函数能够添加参数

def timmer(func):
    def wrapper(*args,**kwargs):
        start_time = time.time()
        res = func(*args,**kwargs)#运行test
        stop_time = time.time()
        print("运行时间" + str(stop_time - start_time))
        return res
    return wrapper

@timmer #test = timmer(test)
def test(name,age):
    time.sleep(3)
    print("函数运行完毕名字 : %s 年龄 %s" %(name,age) )
    return "我是test"

四 : 解压序列

获取列表或元祖可以用解压队列对应的方式
a获取1,b获取2 ,c获取3

a,b,c = (1,2,3)
print(a,b,c)

取出庞大列表的第一项和倒数第一第二项
其中假如想忽略中间的列表,*temp可以用*_替换

a,*temp,b,d= [1,2,3,4,5,6,7]
print(a)
print(b)
print(d)
1
6
7
[2, 3, 4, 5]

python交换变量的另类方式

f1 = 1
f2 = 2
f1,f2 = f2,f1

五 : 装饰器添加参数

① 雏形 :

功能 : 模拟一个用户登录的验证功能+session功能

user_list = [
{'name' : 'sisi','password':'123'},
{'name' : 'keke','password':'123'},
{'name' : 'nana','password':'123'},
]

current_dic = {'username' : None,'login':False}
def auth_func(func):
    def wrapper(*args,**kwargs):

        if current_dic['username'] and current_dic['login']:
            res = func(*args, **kwargs)
            return res
        username = input('用户名 :').strip()
        password = input('密码 :').strip()
        for dic in user_list:
            if username == dic['name'] and password == dic['password']:
                current_dic['username'] = username
                current_dic['login'] = True
                res = func(*args, **kwargs)
                return res
        else:
            print('用户名密码错误')

    return wrapper


@auth_func
def index():
    print("京东主页")

@auth_func
def home(name):
    print(name+"欢迎回家")

@auth_func
def shopping_car(name):
    print("%s的橘子" %name)


index()

home('雪芙')

shopping_car("思思")
② 终极 :

在①中,我们不能选择数据库,所以我们要为装饰器添加一个参数来,让其有选择数据库的功能,所以在①的基础上,外面又嵌套了一层.

@auth(auth_type='filedb') 把@后面看成一个执行的函数返回值是 auth_func其本质还是 @auth_func, 只不过,运行调用一次auth(auth_type='filedb')我们可以在其中做相应的业务逻辑

user_list = [
{'name' : 'sisi','password':'123'},
{'name' : 'keke','password':'123'},
{'name' : 'nana','password':'123'},
]

current_dic = {'username' : None,'login':False}


def auth(auth_type = 'filedb'):

    def auth_func(func):
        def wrapper(*args,**kwargs):
            print(auth_type)

            if auth_type == "filedb":
                if current_dic['username'] and current_dic['login']:
                    res = func(*args, **kwargs)
                    return res
                username = input('用户名 :').strip()
                password = input('密码 :').strip()
                for dic in user_list:
                    if username == dic['name'] and password == dic['password']:
                        current_dic['username'] = username
                        current_dic['login'] = True
                        res = func(*args, **kwargs)
                        return res
                else:
                    print('用户名密码错误')
            elif auth_type == 'ladp':
                print('岑岑')
            else:
                print("其他方式")

        return wrapper
    return auth_func

@auth(auth_type='filedb')
def index():
    print("京东主页")

@auth(auth_type='ladp')
def home(name):
    print(name+"欢迎回家")

@auth(auth_type='xxx')
def shopping_car(name):
    print("%s的橘子" %name)

 index()

 home('雪芙')

shopping_car("思思")

你可能感兴趣的:(Python篇-装饰器)