• 关于装饰器


    装饰器的功能:

        装饰器作用就是给其他函数添加额外功能。

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

    下面通过一段代码来了解一下装饰器的结构和使用方法:

     1 import time
     2 #装饰器模板
     3 def timer(func):
     4     def wrapper():
     5         start_time=time.time()
     6         func()
     7         end_time=time.time()
     8         print("函数执行时间:%s" %(end_time-start_time))
     9     return wrapper
    10 
    11 #测试函数
    12 @timer #等价于test=timer(test)
    13 def test():
    14     time.sleep(2)
    15     print("test函数执行完毕!")
    16 
    17 #执行过程:存在缺点,因为每次都要先调用装饰器函数,在赋值给变量,麻烦!!!
    18 # test=timer(test)
    19 # # test()
    20 
    21 #语法糖@
    22 res=test()
    23 print(res)

    那么现在有一个问题:如果被修饰函数有返回值怎么办?别着急,下面一段代码告诉你!

     1 #Author : Kelvin
     2 #Date : 2019/1/5 16:56
     3 
     4 import time
     5 #装饰器模板
     6 def timer(func):
     7     def wrapper():
     8         start_time=time.time()
     9         res=func()
    10         end_time=time.time()
    11         print("函数执行时间:%s" %(end_time-start_time))
    12         return res
    13     return wrapper
    14 
    15 #测试函数
    16 @timer #等价于test=timer(test)
    17 def test():
    18     time.sleep(2)
    19     print("test函数执行完毕!")
    20     return "这是test的返回值!"
    21 
    22 
    23 res=test()
    24 print(res)

    如果被修饰函数带参数又怎么办呢?继续......

     1 #Author : Kelvin
     2 #Date : 2019/1/5 17:39
     3 
     4 import time
     5 def timer(func):
     6     def wrapper(*args,**kwargs):
     7         start_time=time.time()
     8         func(*args,**kwargs)
     9         end_time=time.time()
    10         print("函数执行时间:%s" %(end_time-start_time))
    11     return wrapper
    12 
    13 @timer
    14 def test(name):
    15     time.sleep(2)
    16     print("%s的test函数执行完毕!"%name)
    17 
    18 res=test("kelvin")
    19 print(res)

    下面我们使用装饰器来完成一个简单的示例(用户登陆成功够才能执行函数内容)

     1 #Author : Kelvin
     2 #Date : 2019/1/5 19:10
     3 
     4 def auth(func):
     5     def wrapper(*args,**kwargs):
     6         name=input("请输入用户名:").strip()
     7         passwd=input("请输入密码:").strip()
     8         if name=="kelvin" and passwd=="123":
     9             res=func(*args,**kwargs)
    10             return res
    11         else:
    12             print("用户名或密码错误!")
    13     return wrapper
    14 @auth
    15 def index():
    16     print("首页!")
    17 
    18 @auth
    19 def home(name):
    20     print("%s的个人首页!"%name)
    21 
    22 @auth
    23 def shopping_car(name):
    24     print("%s购物车!"%name)
    25 
    26 @auth
    27 def order(name):
    28     print("%s订单!"%name)
    29 
    30 index()
    31 home("kelvin")
    32 order("kelvin")
    33 # 输出结果
    34 # 请输入用户名:kelvin
    35 # 请输入密码:123
    36 # 首页!
    37 # 请输入用户名:kelvin
    38 # 请输入密码:123
    39 # kelvin的个人首页!
    40 # 请输入用户名:kelvin
    41 # 请输入密码:123
    42 # kelvin订单!

    根据上面代码,示例存在缺陷,因为每次执行函数都会要求用户输入用户名密码,那么怎么样才能让用户输入一次账号密码后就能随意执行其他函数呢?下面我们来使用装饰器模拟session的功能。

     1 #Author : Kelvin
     2 #Date : 2019/1/5 21:00
     3 
     4 #已注册用户信息
     5 users=[
     6     {"name":"kelvin","passwd":"123"},
     7     {"name":"elvin","passwd":"123"},
     8     {"name":"bob","passwd":"123"},
     9     {"name":"sun","passwd":"123"},
    10 ]
    11 
    12 current_user={"name":None,"login":False}  #模拟session存储用户登录信息
    13 def auth(func):
    14     def wrapper(*args,**kwargs):
    15         if current_user["name"] and current_user["login"]: #如果session中有数据则说明用户已经登录,可以执行函数
    16             res = func(*args, **kwargs)
    17             return res
    18         name=input("请输入用户名:").strip() #如果session中没有记录用户登录信息则要求用户输入账号密码
    19         passwd=input("请输入密码:").strip()
    20         for user in users:
    21             if name==user["name"] and passwd==user["passwd"]:
    22                 current_user["name"]=name
    23                 current_user["login"]=True
    24                 res=func(*args,**kwargs)
    25                 return res
    26         else:
    27             print("用户名或密码错误!")
    28     return wrapper
    29 @auth
    30 def index():
    31     print("欢迎进入首页!")
    32 
    33 @auth
    34 def home(name):
    35     print("欢迎进入%s的个人首页!"%name)
    36 
    37 @auth
    38 def shopping_car(name):
    39     print("查看%s的购物车!"%name)
    40 
    41 @auth
    42 def order(name):
    43     print("查看%s的订单!"%name)
    44 
    45 
    46 
    47 print(current_user) #登录前查看session中的信息
    48 index() #执行index函数
    49 print(current_user) #登陆后查看session中的信息
    50 home("kelvin") #再次执行home函数可直接执行函数,不用输入账号密码
    51 order("kelvin") #再次执行order函数可直接执行函数,不用输入账号密码
    52 
    53 #输出结果:
    54 # {'name': None, 'login': False}
    55 # 请输入用户名:kelvin
    56 # 请输入密码:123
    57 # 欢迎进入首页!
    58 # {'name': 'kelvin', 'login': True}
    59 # 欢迎进入kelvin的个人首页!
    60 # 查看kelvin的订单!

    由于上面的代码中,用户信息直接放在列表中,现实中用户信息是放在各种不同的数据库中,所以如果装饰器能选择用户验证方式最好,怎么实现呢?看下面代码......

     1 # Author : Kelvin
     2 # Date : 2019/1/5 21:00
     3 
     4 # 已注册用户信息
     5 current_user = {"name": None, "login": False}  # 模拟session存储用户登录信息
     6 
     7 
     8 def auth_type(type="fileDB"):
     9     def auth(func):
    10         def wrapper(*args, **kwargs):
    11             print("当前用户认证类型:",type)
    12             if type == "fileDB":
    13                 if current_user["name"] and current_user["login"]:  # 如果session中有数据则说明用户已经登录,可以执行函数
    14                     res = func(*args, **kwargs)
    15                     return res
    16                 name = input("请输入用户名:").strip()  # 如果session中没有记录用户登录信息则要求用户输入账号密码
    17                 passwd = input("请输入密码:").strip()
    18                 for user in open("users", "r+"):
    19                     user = eval(user)
    20                     if name == user["name"] and passwd == user["passwd"]:
    21                         current_user["name"] = name
    22                         current_user["login"] = True
    23                         res = func(*args, **kwargs)
    24                         return res
    25                 else:
    26                     print("用户名或密码错误!")
    27             else:
    28                 print("暂时不支持这种验证类型!")
    29 
    30         return wrapper
    31 
    32     return auth
    33 
    34 
    35 @auth_type(type="fileDB")
    36 def index():
    37     print("欢迎进入首页!")
    38 
    39 
    40 @auth_type(type="fileDB")
    41 def home(name):
    42     print("欢迎进入%s的个人首页!" % name)
    43 
    44 
    45 @auth_type(type="fileDB")
    46 def shopping_car(name):
    47     print("查看%s的购物车!" % name)
    48 
    49 
    50 @auth_type(type="fileDB")
    51 def order(name):
    52     print("查看%s的订单!" % name)
    53 
    54 
    55 print(current_user)  # 登录前查看session中的信息
    56 index()  # 执行index函数
    57 print(current_user)  # 登陆后查看session中的信息
    58 home("kelvin")  # 再次执行home函数可直接执行函数,不用输入账号密码
    59 order("kelvin")  # 再次执行order函数可直接执行函数,不用输入账号密码
    60 
    61 #输出结果:
    62 # {'name': None, 'login': False}
    63 # 当前用户认证类型: fileDB
    64 # 请输入用户名:kelvin
    65 # 请输入密码:123
    66 # 欢迎进入首页!
    67 # {'name': 'kelvin', 'login': True}
    68 # 当前用户认证类型: fileDB
    69 # 欢迎进入kelvin的个人首页!
    70 # 当前用户认证类型: fileDB
    71 # 查看kelvin的订单!

    这种方式很少使用,最常用的还是前面的装饰器使用方式,应把主要精力放在前面装饰器模式的使用上。

    多练习,多思考,越努力,越幸运!

  • 相关阅读:
    UMeng SDK(友盟) 之 用户反馈
    CCSprite 实现书本翻页效果(quick cocos 2dx)
    quick-cocos2d-x 调用友盟(UMeng)的社区分享(Android平台)
    为精灵添加一些特殊的移动缩放动作,特效
    判断是否点击到了精灵(Sprite)
    quick-cocos-2dx学习之【scheduler.lua】
    quick-cocos-2dx学习之【init.lua】
    C/C++的头文件何处安身的问题
    Tomcat性能优化
    Tomcat基本原理
  • 原文地址:https://www.cnblogs.com/sun-10387834/p/10226461.html
Copyright © 2020-2023  润新知