zoukankan      html  css  js  c++  java
  • 装饰器decorator

    Tutorial:

    https://www.python-course.eu/python3_decorators.php

     先运行装饰器,再运行被包装的函数

    装饰器使用的特点:
    1 必须用函数作为参数传递给另一个函数
    2 要有闭包的特点

    装饰器范例:

     1 #定义一个装饰器: 用函数作为参数传给另一个函数
     2 def decorator(func):
     3     a=100
     4     print('wrapper外层打印测试')
     5     def wrapper():
     6         print('------>111111')
     7         func()
     8         print('------>222222')
     9         print(a)
    10     print('wrapper加载完成')
    11     return wrapper
    12 
    13 #使用装饰器:要给house()函数加装饰器,则在def house()上面@decorator
    14 @decorator #此处的@,表示运行decorator()
    15 def house():
    16     print('我是毛坯房')
    17 #house()
    18 print(house)
    19 
    20 #不改变原函数的前提下,对其进行修改
    21 
    22 def house1():
    23     house()
    24     print('刷漆')
    25     print('铺地板')
    26 #house1() #等同于装饰器的效果
    27 house()
    28 '''
    29 @decorator表示:
    30 1 house是被装饰函数
    31 2 将被装饰函数作为参数传给装饰器decorator
    32 3 底层执行了装饰器函数decorator
    33 因此一旦@了,则会执行decorator里面的print命令
    34 4 将返回值赋值给house
    35 decorator返回的wrapper并没有变量接收,但默认是由house接收,参考print(house)结果
    36 print(house) - <function decorator.<locals>.wrapper at 0x050B32B8>
    37 '''

    范例2:

     1 import time
     2 def decorate(func):
     3     def wrapper():
     4         print('正在校验。。。')
     5         time.sleep(2)
     6         print('校验完成')
     7         func()
     8     return wrapper
     9 
    10 @decorate
    11 def f1():
    12     print('---f1---')
    13 @decorate
    14 def f2():
    15     print('---f2---')
    16 
    17 f1()
    18 f2()

    结果:

    1 正在校验。。。
    2 校验完成
    3 ---f1---
    4 正在校验。。。
    5 校验完成
    6 ---f2---

    3. 带参数的装饰器:

     1 #装饰器范例2,带参数
     2 import time
     3 def decorate(func): #不论传过来的是什么参数,都可以识别,就是万能装饰器
     4     def wrapper(*argv, **kwargv): #*argv这种只能接收非关键字参数,**kwargv可以接收关键字参数,
     5     #**kwargv会自动把传过来的变为字典{'class1':1905}
     6         print('正在校验。。。')
     7         time.sleep(2)
     8         print('校验完成')
     9         func(*argv, **kwargv) #func()可能是f1,f2,f3
    10     return wrapper
    11 
    12 @decorate
    13 def f1(n):
    14     print('---f1---',n)
    15 
    16 @decorate
    17 def f2(name, age):
    18     print('---f2---',name,age)
    19 
    20 @decorate
    21 def f3(students, class1 = '1905'):
    22     print('{}班级的学生如下:'.format(class1))
    23     for stu in students:
    24         print(stu)
    25 
    26 def f4():
    27     print('---f4---')
    28 
    29 f1(5) #经过装饰器装饰后的f1已经是wrapper了,因此需要让wrapper也能接收一个参数
    30 f2('haha','5')
    31 f3([1,2], class1='1904')
    32 f3([1,2])
    33 #f4()

    结果:

     1 正在校验。。。
     2 校验完成
     3 ---f1--- 5
     4 正在校验。。。
     5 校验完成
     6 ---f2--- haha 5
     7 正在校验。。。
     8 校验完成
     9 1904班级的学生如下:
    10 1
    11 2
    12 正在校验。。。
    13 校验完成
    14 1905班级的学生如下:
    15 1
    16 2

    4. 多层装饰器:

     1 '''
     2 如果装饰器是多层的,哪个装饰器离要被装的函数近,就先执行哪个装饰器
     3 '''
     4 
     5 def decorator1(func):
     6     print('------1, start') #当使用装饰器时,@后,就会打印装饰器内的内容
     7     def wrapper(*argv, **kwargv):
     8         func()
     9         print('刷漆')
    10 
    11     print('------1, end')
    12     return wrapper
    13 
    14 def decorator2(func):
    15     print('------2, start')
    16     def wrapper(*argv, **kwargv):
    17         func()
    18         print('铺地板')
    19     print('------2, end')
    20     return wrapper
    21 
    22 
    23 @decorator2 #此处的顺序是哪个装饰器离要被装的函数近,就先执行哪个装饰器,@的时候会执行装饰器内的print
    24 @decorator1
    25 def house():
    26     print('我是毛坯房')
    27 
    28 house()

    结果:

    1 ------1, start
    2 ------1, end
    3 ------2, start
    4 ------2, end
    5 我是毛坯房
    6 刷漆
    7 铺地板

    5. 带参数的装饰器

     1 #带参数的装饰器
     2 '''
     3 带参数的装饰器是三层的
     4 
     5 '''
     6 def outer(a): #第一层用来接收装饰器传过来的参数的 100
     7     def decorate(func): #第二层负责接收内层函数的
     8         def wrapper(*argv, **kwargv): #第三层负责接收函数的实参的 20199093
     9             func(*argv)
    10             print('--->铺地砖{}块'.format(a))
    11         return wrapper #第二层返回的是第三层的函数名
    12     return decorate #第一层函数返回的是第二层的函数名
    13 
    14 #在装饰器中可能传参
    15 @outer(a=10)
    16 def house(time):
    17     print('我{}拿到钥匙,是毛坯房'.format(time))
    18 
    19 @outer(100)
    20 def street():
    21     print('新修的街道叫哈哈')
    22 '''
    23 装饰器的目的在于,让有共同点的代码都被具有该共同点的装饰器锁装饰
    24 '''
    25 
    26 house('20190903')
    27 
    28 street()

    结果:

    1 我20190903拿到钥匙,是毛坯房
    2 --->铺地砖10块
    3 新修的街道叫哈哈
    4 --->铺地砖100块

    6. 装饰器应用

     1 #开发:登录验证
     2 import time
     3 
     4 islogin = False #默认没有登录的
     5 #定义一个登录函数
     6 def login():
     7     username = input('输入用户名: ')
     8     password = input('输入密码:')
     9     if username == 'admin' and password == '123456':
    10         return True
    11     else:
    12         return False
    13 
    14 #定义装饰器进行付款验证的
    15 def login_required(func):
    16     def wrapper(*argv, **kwargv):
    17         global islogin
    18         print('------付款------')
    19         #验证用户是否登录
    20         if islogin:
    21             func(*argv, **kwargv)
    22         else:
    23             #跳转到登录界面
    24             print('用户没有登录,不能付款')
    25             islogin = login()
    26             print('result: ',islogin)
    27     return wrapper
    28 
    29 
    30 
    31 @login_required
    32 def pay(money):
    33     print('正在付款,付款金额是:{}元'.format(money))
    34     print('付款中。。。')
    35     time.sleep(2)
    36     print('付款完成')
    37 
    38 #调用付款:
    39 pay(100) #相当于wrapper(100),argv= 100
    40 
    41 pay(80)
    42 #调用第一个pay时没付款成功,跳到登录界面了,调用第二个pay时直接付款成功,因为pay(100)时已经登录成功了

    结果:

    1 ------付款------
    2 用户没有登录,不能付款
    3 输入用户名: admin
    4 输入密码:123456
    5 result:  True
    6 ------付款------
    7 正在付款,付款金额是:80元
    8 付款中。。。
    9 付款完成

    第一次想要付款时,因为没有登录,所有不能付款,需要输入用户名和密码,再付款

    第二次付款时,因为第一次已经登录过了,因此可以直接付款

  • 相关阅读:
    druid-1.0.13 数据库配置文件密码加密
    PostConstruct注解
    easyui formatter 返回easyui组件
    小师妹问 easyUI mergeCells 行合并后表头和内容对不齐
    Java Split以竖线作为分隔符
    Integer比较值的时候小心使用
    js 关键字 in
    Asp.net中防止用户多次登录的方法
    C#取得站点跟目录
    解读支付宝接口实现步骤
  • 原文地址:https://www.cnblogs.com/vigossr/p/11413193.html
Copyright © 2011-2022 走看看