python基础之装饰器详解

一、前言

装饰器:本质就是函数,功能是为其他函数添加附加功能

原则:

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

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

二、高阶函数

高阶函数定义:

  •     1、函数接收的参数是一个函数
  •     2、函数的返回值是一个函数名
  •     3、满足上述条件任意一个,都可以称为高阶函数

test 函数是高阶函数,接受了一个foo 作为参数

import timedef foo():    time.sleep(3)    print("sleep 3s") def test(func):    start_time = time.time()    func()    stop_time = time.time()    print("函数的运行时间是: %s" % (stop_time - start_time)) test(foo)

timer 是一个高阶函数,这个函数返回值是一个函数

import timedef foo():    time.sleep(3)    print("sleep 3s") def timer(func):    start_time = time.time()    func()    stop_time = time.time()    print("执行时间{}".format(stop_time - start_time))    return funcfoo = timer(foo)foo()# 结果: 多运行了一次

三、函数嵌套

在函数里面定义函数,变量的作用域和生存周期不变。

def father(name):    print("father name: %s" % name)    def son():        print("son name: %s" % name)    son()father("xu1") # 结果:#     father name: xu1#     son name: xu1

四、装饰器

实现一个计算函数执行时间的函数作为装饰器,用来计算被装饰函数的执行时间并打印

import time def timer(func):  # 实现一个计算函数执行时间的函数作为装饰器,用来计算被装饰函数的执行时间并打出    def wrapper():        start_time = time.time()        func()        stop_time = time.time()        print("运行时间: %s" % (stop_time - start_time))    return wrapper # def test():  # 不使用装饰器的同等实现#     time.sleep(3)#     print("test sleep 3s")## test = timer(test)  # 返回的是 wrapper 的地址# test()  # 执行的是 wrapper  @timerdef test():  # 装饰器的实现    time.sleep(3)    print("test sleep 3s") test()  # 执行的是 wrapper# 结果:#     test sleep 3s#     运行时间: 3.000915050506592

4.1 被装饰方法带返回值

import time  def timer(func):    def wrapper():        start_time = time.time()        res = func()  # 执行被装饰方法        stop_time = time.time()        print("运行时间: %s" % (stop_time - start_time))        return res  # 接受正在调用的方法的返回值,并返回    return wrapper  @timerdef test():    time.sleep(3)    print("test sleep 3s")    return "test return ok"  print(test())  # 执行的是 wrapper# 结果:#     test sleep 3s#     运行时间: 3.0002923011779785#     test return ok

4.2 被装饰方法带参数

import time  def timer(func):    """        *args:将被修饰方法传入的非关键字参数打包为元组 args        **kwargs: 将被修饰方法传入的关键字参数打包为字典 kwargs    """    def wrapper(*args, **kwargs):        start_time = time.time()        res = func(*args, **kwargs)  # *args 拆解元组,按顺序传给被修饰函数; **kwargs:拆解字典        stop_time = time.time()        print("运行时间: %s" % (stop_time - start_time))        return res    return wrapper  @timer  # 给test 方法添加计算执行时间的装饰器def test(name, age):    time.sleep(3)    print("name = {}, age = {}".format(name, age))    return "test return ok"  # 调用被装饰器装饰的方法print(test("xu", 100))  # 执行的是 wrapper# 结果:#     name = xu, age = 100#     运行时间: 3.000420331954956#     test return ok

4.3 验证功能装饰器

假如 index() 、home()、shopping_car() 三个方法都需要登录后才能访问(无法访问时里面不输入对应内容),正常情况下只需登录一次,后面访问其他方法就无需再次登录。

可以通过@auth_fun装饰器进行验证用户是否登录,如果没有就让用户输入账号密码,用户账号密码正确的记录当前登录的用户,其他方法无需再次登录。

# 用户列表user_list = [    {'name': 'xu1', 'passwd': '123'},    {'name': 'xu2', 'passwd': '123'},    {'name': 'xu3', 'passwd': '123'},    {'name': 'xu4', 'passwd': '123'},]# 当前登录的用户current_dic = {"username": None, "login": False}  # 验证用户是否登录的装饰器#   如果用户没有登录,让用户输入账号密码,校验通过记录用户状态def auth_fun(func):    def wrapper(*args, **kwargs):        if current_dic["username"] and current_dic['login']:            res = func(*args, **kwargs)            return res        username = input("请输入用户名:")        pw = input("请输入密码:")        for u in user_list:            if u["name"] == username and u["passwd"] == pw:                current_dic["username"] = username                current_dic["login"] = True                res = func(*args, **kwargs)                return res        else:            print("用户没有注册!")    return wrapper  @auth_fundef index():    print("this is index")  @auth_fundef home():    print("this is home page")  @auth_fundef shopping_car():    print("this is shopping car")  index()  # 输入用户密码home()  # index 已经登录,无需在输入shopping_car()  # index 已经登录,无需在输入# 结果:#     请输入用户名:xu1#     请输入密码:123#     this is index#     this is home page#     this is shopping car

4.4 验证功能装饰器――带参数

 装饰器带参数,最简单的操作就是可以对被装饰的函数进行区别处理。

# 用户列表user_list = [    {'name': 'xu1', 'passwd': '123'},    {'name': 'xu2', 'passwd': '123'},    {'name': 'xu3', 'passwd': '123'},    {'name': 'xu4', 'passwd': '123'},]# 当前登录的用户current_dic = {"username": None, "login": False} """    注意:带参数的装饰器会比没有带参数的装饰器多嵌套一层函数(多了auth)        调用方式是 @auth(auth_type="type1"), 返回 auth_fun,        也就是说 @auth(auth_type="type1")相当于 @auth_fun        但是 auth_fun 函数所在的嵌套作用域多了一个 auth_type 的变量"""def auth(auth_type="type1"):    def auth_fun(func):        def wrapper(*args, **kwargs):            if auth_type == "type1":                if current_dic["username"] and current_dic['login']:                    res = func(*args, **kwargs)                    return res                username = input("请输入用户名:")                pw = input("请输入密码:")                for u in user_list:                    if u["name"] == username and u["passwd"] == pw:                        current_dic["username"] = username                        current_dic["login"] = True                        res = func(*args, **kwargs)                        return res                else:                    print("用户没有注册!")            elif auth_type == "type2":                print("不用授权直接登录: type = {}".format(auth_type))                res = func(*args, **kwargs)                return res            else:                print("其他type没有实现")        return wrapper    return auth_fun  """    auth_fun = @auth(auth_type="type1")     auth_fun 所在的嵌套与将有一个 auth_type 变量    然后通过 @auth()方法返回的对象注解 index,相当于 @auth_fun 注解index 方法,最后得到 wrapper 对象"""@auth(auth_type="type1")def index():    print("this is index")  @auth(auth_type="type2")def home():    print("this is home page")  @auth(auth_type="type3")def shopping_car():    print("this is shopping car")  home()  # 注意:auth_type="type2",这个方法无需登录可以直接执行index()  # 注意:auth_type="type1",需要登录shopping_car()  # 注意:auth_type="type3",没有做处理# 结果:#     不用授权直接登录: type = type2#     this is home page#     请输入用户名:xu1#     请输入密码:123#     this is index#     其他type没有实现

到此这篇关于python基础之装饰器详解的文章就介绍到这了,更多相关python装饰器内容请搜索 以前的文章或继续浏览下面的相关文章希望大家以后多多支持 !

相关文章

发表新评论