有参装饰器、多层语法糖

一、双层语法糖

'''双层语法糖'''
import time

'''验证装饰器'''
def login(xxx):  # 步骤5:无代码块,故执行返回值 返回count
    def count(*args,**kwargs):  # 步骤8:所以运行login内层函数 运行函数体
        '''装饰对象被调用前,添加的新功能'''
        username = input('请输入用户名>>>:').strip()
        password = input('请输入密码>>>:').strip()
        if username == 'chen' and password == '123':  # 步骤9:运行验证判断正确后进入

            rel = xxx(*args,**kwargs)  # 步骤10:rel = get_time()
            '''装饰对象被调用后,添加的新功能'''
            return rel  # 步骤11:返回值rel就是get_time()
        else:
            print('请输入正确的账号或密码')
    return count  # 步骤6:因为是双层语法糖,这里就是最后一层,所以:show=count

'''计算执行时间装饰器'''
def outer(zzz):  # 步骤2:无代码块,故执行第一层函数的返回值,返回gei_time
    def get_time(*args,**kwargs):   # :步骤12:进入outer函数的内层函数中,运行函数体
        '''被装饰对象调用前,添加的新功能'''
        start_time = time.time()  # 步骤12-1:运行定义的起始时间
        res = zzz(*args,**kwargs)  # 步骤13:这里的res=show()
        '''被装饰对象调用后,添加的新功能'''
        end_time = time.time()  # 步骤13-1:运行定义的结束时间
        print('执行函数所消耗的时间>>>>:%s' % (end_time - start_time))  # 步骤13-2:打印运算结果
        return res  # 步骤14:返回res,res就是show()
    return get_time  # 步骤3: 因为是做双层语法糖所有这里是get_time=outer(show) 只有是最后一层才会用show=函数名()

@login  # 步骤4:index=login(get_time)
@outer  # 步骤1:get_time=outer(show)
def show():  # 步骤15:运行函数show内部代码
    time.sleep(2)  # 步骤15-1:使该函数睡眠2秒后再继续执行
    print('I AM KING')

show()  # 步骤7:因为步骤6是show=count,所以运行 show()=count()


'''
双层语法糖内部运行步骤:
1.先运行装饰器outer
2.因为有语法糖所以函数show会直接被装饰器outer当成它的形参
3.因没有函数体代码,故直接运行返回值,它的返回值是它的第二层函数的函数名
4:所以就得到了get_time=outer(show)(这里为什么是get_time,是因为不是最后一层,
所以不能直接用show来)

5.继续运行第二个装饰器login
6.因为有语法糖所有上层函数的函数名(get_time)会被直接当成装饰器login的形参
7.因没有函数体代码,故直接运行返回值,它的返回值也是它的第二层函数的函数名
8.所以就得到了show=login(get_time)>>>>>>count,
(因为这里是最后一层装饰器所以可以直接用show来等于)

9.调用show(),因为show在步骤7那里拿到的是count,所有show()======count()
10.所有运行装饰器login内层函数count,运行它的函数体代码,得到了一个rel=xxx()的值,
而xxx就是装饰器第一层函数的形参get_time,所以就是rel=get_time()

11.count函数运行返回值,返回值是rel就是get_time(),所有运行装饰器outer的内层函数
12.运行get_time函数中的函数体代码,而后得到了res=zzz(),
而这个zzz就是第一层装饰器的形参show,故就是res=show()

13.继续运行函数体代码后,执行返回值,返回res,而res就是show(),
故执行调用真正的show函数

14.最后运行函数show的函数体代码
'''

二、三层语法糖(多层)

	'''与双层语法糖的内部运行是一样的,故这里就不详细写步骤了'''
	def outter1(func1):
    print('加载了outter1')
    def wrapper1(*args,**kwargs):
        print('执行了wrapper1')
        res1=func1(*args,**kwargs)
        return res1
    return wrapper1

	def outter2(func2):
	    print('加载了outter2')
	    def wrapper2(*args,**kwargs):
	        print('执行了wrapper2')
	        res2=func2(*args,**kwargs)
	        return res2
	    return wrapper2
	
	def outter3(func3):
	    print('加载了outter3')
	    def wrapper3(*args,**kwargs):
	        print('执行了wrapper3')
	        res3=func3(*args,**kwargs)
	        return res3
	    return wrapper3
	
	
	@outter1
	@outter2
	@outter3
	def index():
	    print('hello world')
	
	index()
	'''
	判断以上三层语法糖及函数index的打印顺序
	最终得到的顺序结果为:
	1.加载了outter3    2.加载了outter2
	3.加载了outter1    4.执行了wrapper1
	5.执行了wrapper2   6.执行了wrapper3
	7.hello world
	'''

三、装饰器的修复技术(了解)

import time # 时间模块
from functools import wraps # 修复技术模块
'''装饰器的修复技术'''
def outer(xxx):
    @wraps(xxx)  # 修复技术
    def inner(*args,**kwargs):
        start_time = time.time()  # 设定的起始时间
        rel=xxx(*args,**kwargs)
        end_time = time.time()  # 设定的结束时间
        print('执行所消耗的时间>>>>:%s' % (end_time - start_time))
        return rel
    return inner

@outer
def index():
    print('hello world')

'这个是没加装饰器运行打印的结果'得到的是index的内存地址
print(index) # <function index at 0x000001CABE0A9820> 

'这个是加装饰器没加修复技术运行打印的结果'得到的是伪装的内存地址
print(index)
#<function outer.<locals>.inner at 0x000002C12FB591F0>

'这个是既加了装饰器又加了修复技术运行打印的结果'得到的是index的内存地址
print(index) # <function index at 0x000001DDB4AC91F0>

	'''修复技术就是为了让装饰器伪装的更好'''

四、有参装饰器

	'''有参装饰器'''
def outter(type):  # 这里是有参装饰器
    def login_auth(xxx):  # 这里是无参装饰器,参数个数只能有一个
        def auth(*args,**kwargs): # 这里是专门接收被装饰对象传参的
            '''
			校验用户数据  数据的来源可以有很多  比如全局字典 
			全局列表  文本文件  数据库
            数据的来源不同  处理方式就不同  对应的代码编写就不一样
            分支结构处理  然后根据不同的参数提示  匹配不同的流程

            根据不同的参数用户名和密码来自不同的位置
             1. 文件中获取用户名和密码
             2. 从MySQL中获取用户名和密码
             3. 从oracle中获取用户名和密码
            '''
            if type == '1':
                print('用户名和密码来自文件')
            elif type == '2':
                print('用户名和密码来自MySQL')
            elif type == '3':
                print('用户名和密码来自Oracle')

            # username = input('username>>>:').strip()
            # password = input('password>>>:').strip()
            # if username == ' ' and password == ' ':
            rel = xxx(*args,**kwargs)
            return rel
            # else:
            #     print('账号或密码错误')
        return auth
    return login_auth


@outter(1)
def home(): # 来自文件
    pass
home()

@outter(2)
def index(): # 来自MySQL
    pass
index()

@outter(3)
def func(): # 来自Oracle
    pass
func()

'''
      函数名加括号  执行优先级最高
      @outter('3')
          左侧是语法糖结构  右侧是函数名加括号结构
            先执行函数调用  outter('3')  返回值是login_auth
            在执行语法糖结构  @login_auth
          发现最后还是一个普通的装饰器
      有参装饰器目的仅仅是给装饰器传递额外的参数
          装饰器最多的就三层嵌套
      并且三层嵌套的结构使用频率不高(最多是使用别人写好的有参装饰器)
          from functools import wraps
          @wrps(xxx)
'''
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值