一、旋量群
1、为何要将旋量群和点缀器放到一同阐释?
即使点缀器这类是两个旋量群,透过旋量群手提袋某一的机能后,再为许多表达式展开点缀,使其在不发生改变标识符的情况下保有旋量群里头的扩充机能。因而,在介绍点缀器以后,要先介绍旋量群,为自学点缀器打好此基础。
2、甚么是旋量群?
旋量群是在表达式中表述另两个表达式,他们称作内层表达式和内层表达式,内层表达式采用内层表达式的表达式,内层表达式将内层表达式这类做为codice展开回到。
他们先用几段单纯的代码来探究那个抽象化的难题,标识符如下表所示:
# 表述内层表达式 def outer_func(x): # 表述内层表达式表达式 y = 10 # 表述内层表达式 def inner_func():z = x + y print(结论是:, z) # 将内层表达式这类做为codice回到 return inner_func # 建立两个表达式,并初始化内层表达式 result = outer_func(8) # 内层表达式codice是内层表达式这类,因而建立的表达式对准的是内层表达式inner_func的物理地址 print(result) # 初始化那个表达式代表者的表达式就相等于初始化了内层表达式 # result()表达式能出访outer_func表达式里头的表达式x和y,并原始数据和输入 result() 输入结论: <function outer_func.<locals>.inner_func at 0x000002AE44D86520> 结果是:18★ 这是两个完整的旋量群!
3、旋量群的作用
旋量群有两个作用:1.读取表达式内部的表达式;2.延长表达式内部表达式的生命周期
在这里单单看旋量群的作用感觉没有甚么实际意义,其实旋量群的作用是用来写点缀器!
下面再用两个货币汇率兑换的例子来辅助理解一下旋量群,标识符如下表所示:
# 建立旋量群表达式 # 表述两个货币汇率兑换表达式,这是内层表达式 def exchange(x): # 表述内层表达式,通常采用wrapper命名,wrapper是手提袋的意思 # 把内层表达式的表达式x装进两个手提袋,展开加工 def wrapper(y): # 在内层表达式中采用内层表达式的表达式x # 根据内层表达式x的值确定兑换汇率 if x == 美元: rate = 7.15 elif x == 欧元: rate = 7.45 elif x == 英镑: rate = 8.64 else: rate = 0 # 内层表达式将传进来的表达式y的值乘以汇率,最终传送出去 return rate * y # 内层表达式的codice是内层表达式这类,把里头的手提袋传递出去 return wrapper # 分别用美元、欧元和英镑为参数建立三个表达式 # 由于exchange的codice是内层表达式这类,因而建立的三个表达式ex1、ex2和ex3相等于类的对象 # 虽然内层表达式exchange已经执行完毕,但是其内部表达式x的值依然保存在内存中,随时能初始化 # 这是旋量群的特点:1.读取表达式内部的表达式;2.延长表达式内部表达式的生命周期 ex1 = exchange(美元) ex2 = exchange(欧元) ex3 = exchange(英镑) # 直接初始化刚建立的表达式类型表达式,并将要计算的数值传进去,输入相应的兑换值 print(ex1(1)) print(ex2(10)) print(ex3(5)) print(ex3) 输入结论: 7.15 74.5 43.2 <function exchange.<locals>.wrapper at 0x0000019AEAB6F2E0>二、点缀器
1、点缀器描述
顾名思义,点缀器是两个能点缀别人的容器,那个容器是两个表达式,确定地说是两个旋量群表达式。
原有两个表达式,在不发生改变其原有标识符的情况下,为其增加扩充机能,原有初始化方式保持不变。这是点缀器的作用。
2、点缀器原理
首先表述两个旋量群(即点缀器),在旋量群的内层表达式(手提袋)里写入扩充机能标识符,同时在内层表达式里初始化执行被点缀的表达式。
然后把旋量群以@function的形式加在所须点缀的表达式上方,系统执行时遇到点缀器@function就首先执行点缀器表达式即旋量群,同时将原有被点缀的表达式以参数形式传入点缀器表达式中,再将点缀器的codice(内层表达式地址)赋值给原有表达式。
★ 其实点缀器是把原有表达式展开了重定向,先去执行点缀器的内层表达式里头的机能再执行其这类机能,实现点缀效果。
3、应用场景
假设你写了两个表达式,你的其它项目里导入并采用了那个表达式;或者你将那个表达式打包分享到网上,别人导入并采用了你写的表达式;或者你和同事共同开发两个项目,而你同事负责的那部分项目里用到了你的表达式,等等。在这种情况下,如果你想修改那个表达式增加许多机能,那么其它所有初始化那个表达式的标识符里就有可能会发生错误,这时就用到了点缀器。
4、点缀器的常见机能
引入日志表达式执行时间统计执行表达式前预备处理执行表达式后清理机能权限校验等场景缓存5、点缀器实例演示
他们先表述两个表达式,假设实现的是聊天室机能,这里只用一句输入语句代替,主要演示的是点缀器如何表述和采用。标识符如下表所示:
def chat_room(): print(在聊天室里聊天) chat_room() 输入结论: 在聊天室里聊天从标识符和运行结论来看,那个聊天室表达式没有用户名、密码和验证码等验证环节,现在要在不改动其标识符和初始化方式的情况下,采用点缀器来为那个表达式增加这些验证机能,标识符如下表所示:
# 现在要求不发生改变chat_room表达式的标识符,而为其增加身份验证机能 # 首先表述旋量群表达式,要带有表达式参数 # 参数func用来接收原有表达式chat_room def decfunc(func): # 表述内层表达式即旋量群,最好加上*arge,**kwarge这两个参数,能应对所有情况 def wrapper(*args, **kwargs): # 表述登录次数变量 count = 1 # 当输错次数达到3次就结束程序 while count <= 3: username = input(请输入用户名:) password = input(请输入密码:) if username == admin and password == 1111: # 用户名和密码正确,开始初始化执行内层表达式传进来的表达式对象 func(*args, **kwargs) # 如果旋量群表达式加了*arge和**kwarge,那么这里初始化时要也加上 return # 如果被点缀的表达式具有codice,那么wrapper那个内层表达式要要有codice else: print(用户名或密码错误,请重新输入…) count += 1 print(输入超过3次,系统退出!) # 将内层表达式做为codice回到 return wrapper # 补充:能做多层点缀器,执行顺序是从上到下,这里他们再加两个验证码的点缀器 def yz_code(func): def wrapper(*args, **kwargs): code = input(请输入验证码:) if code == 4321: # 验证码正确,开始初始化原始表达式,即进入聊天室 func(*args, **kwargs) else: print(验证码错误,退出系统!) return return wrapper # 开始点缀原表达式,这种形式也被形象的称作语法糖 @decfunc # 用户名密码点缀器 @yz_code # 验证码点缀器 def chat_room(): # 原表达式 print(在聊天室里聊天) chat_room() 输入结论: 请输入用户名:admin 请输入密码:1111 请输入验证码:4321 在聊天室里聊天点缀器能是一层也能是多层,以上标识符实现的是两层点缀器。透过标识符及输入结论能看到,原聊天室表达式标识符没有改动,初始化方式也没有改动,但是运行后增加了用户名和密码验证机能,然后又增加了验证码机能,验证全都透过后才执行原来的聊天室表达式。
以上标识符执行的简要流程:
首先遇到用户名密码点缀器@decfunc,@decfunc开始对下面表达式展开点缀@decfunc的下面是@yz_code,因而表达式yz_code被做为参数传入decfunc表达式里@yz_code这类也是点缀器,下面的chat_room表达式又做为参数传入yz_code表达式里最后从上到下开始执行,用户名密码——验证码——聊天室。也能这样理解:
聊天室表达式chat_room首先被传入离它最近的验证码点缀器@yz_code里,然后codice又做为参数传入到上一层点缀器@decfunc里,最后开始顺序执行。