python基础之装饰器详解

作者:思想流浪者 时间:2022-05-22 15:26:38 

一、前言

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

原则:

  •     1、不修改被修饰函数的源代码

  •     2、不修改被修饰函数的调用方式

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

二、高阶函数

高阶函数定义:

  •     1、函数接收的参数是一个函数

  •     2、函数的返回值是一个函数名

  •     3、满足上述条件任意一个,都可以称为高阶函数

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


import time
def 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 time
def 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 func
foo = 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

@timer
def 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

@timer
def 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_fun
def index():
   print("this is index")

@auth_fun
def home():
   print("this is home page")

@auth_fun
def 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没有实现

来源:https://blog.csdn.net/qq_30346413/article/details/115585209

标签:python,装饰器
0
投稿

猜你喜欢

  • python实现求两个字符串的最长公共子串方法

    2021-08-02 21:14:08
  • Python 实现过滤掉列表中唯一值

    2021-09-26 23:13:55
  • 围观tangram js库

    2024-04-29 13:38:39
  • python反爬虫方法的优缺点分析

    2023-09-07 11:38:02
  • python中time.ctime()实例用法

    2022-11-09 05:25:32
  • MSSQL MySQL 数据库分页(存储过程)

    2012-01-29 18:30:20
  • 浅谈Pytorch中的torch.gather函数的含义

    2022-12-26 02:25:54
  • Django 如何从request中获取前端数据

    2023-06-22 06:52:16
  • sql server海量数据库的查询优化及分页算法方案

    2010-07-02 21:17:00
  • 10分钟学会Google Map API (二)

    2009-06-07 18:14:00
  • 详解在SQLPlus中实现上下键翻查历史命令的功能

    2024-01-27 01:51:36
  • pyecharts结合flask框架的使用

    2022-12-01 18:37:25
  • 《色彩解答》系列之二 色彩比例

    2008-02-17 14:38:00
  • 使用Python对Dicom文件进行读取与写入的实现

    2022-05-30 12:18:27
  • MySQL中一条update语句是如何执行的

    2024-01-16 23:57:43
  • Oracle row_number() over()解析函数高效实现分页

    2011-12-01 10:33:07
  • Python 如何实现批量转换视频音频的采样率

    2022-06-30 11:16:46
  • Go本地测试小技巧解耦任务拆解

    2023-08-29 14:09:26
  • python time.strptime格式化实例详解

    2022-03-25 19:13:02
  • 详解Python+Pyecharts实现漏斗图的绘制

    2022-07-07 10:22:42
  • asp之家 网络编程 m.aspxhome.com