Python装饰器
装饰器简介
装饰器的作用: 在保证原来函数不变的情况下,直接给这个函数增加新的功能
#装饰器 ''' 在不修改源代码的基础上,给函数增加新的功能 ''' #装饰器会将被装饰的函数当作参数传递给装饰器同名的函数 #添加装饰器,需要: # 1.存在闭包 # 2.存在需要被装饰的函数
装饰器使用条件
#使用条件 ''' Python的装饰器,闭包是进入Python高级语法的基础,在使用 装饰器之前,有以下条件: 1.存在闭包 2.存在需要被装饰的函数 3.理解函数地址值的概念 '''
函数地址概念
当我们定义一个函数,使用print()方法打印其地址,每个地址唯一
#定义函数func def func(): print("你好") print(func) # <function func at 0x0000014C7AF31EA0>
闭包
#闭包 ''' 闭包可以理解成"定义在一个函数内部的函数", 在一个函数中嵌套定义了一个函数,内函数里运用了外函数的临时变量, 并且外函数的返回值(return)是内涵上的引用(地址值),这样就构成了一个闭包 ''' #条件 # 1.存在函数的嵌套关系 # 2.内层函数引用了外层函数的变量 # 3.外城函数返回内层函数的地址值 def out_func(num): #外部函数 def in_func(in_num): #内部函数 print("函数的外部变量",num) #打印外部函数传入的num print("函数的内部变量",in_num) #打印内部函数传入的in_num return in_func #返回函数名存放的地址值 result = out_func(10) #传入函数参数,返回in_func的地址,相当于result = in_func() print(result) #<function out_func.<locals>.in_func at 0x000002510F8437B8> result(5) #传入参数值5,调用in_func()
装饰器步骤
1.闭包
#==================闭包======== # 1.存在函数的嵌套关系 # 2.内层函数引用了外层函数的变量 # 3.外层函数返回内层函数的地址值 #外部函数为创建函数 def welcome(func): #外部函数当作变量传入 #内部函数是整理逻辑 def in_func(): print("欢迎光临") #调用被装饰的函数,实现两个函数体都被执行 #且实现内部函数引用外部函数的变量 func() #调用外部函数 #输出传入函数的地址值 print("func的地址值",func) #0x000001AB7F5237B8 #输出内部函数的地址值 print("in_func函数的地址值",in_func) #0x000001AB7F523840 return in_func #返回内部函数的地址
2.装饰器使用@闭包外函数的名称的形式
@welcome def login(): print("登陆成功")
装饰器下面的函数相当于传入装饰器同名函数的参数中
3.调用被装饰的函数
#调用被装饰的函数 login() #输出login函数的地址值 print("login函数的地址值",login) #0x000001AB7F523840
从上述的输出地址过程中可以发现,被修饰的函数和闭包中的内部函数地址相同,说明是同一个函数的不同名;所有的功能和逻辑在闭包中,而被装饰的函数只是被闭包进行调用,在调用的过程中是闭包的内部函数自我调用的过程,因为内部函数中的函数是相同的函数

实战-计算器
import win32com.client class Calc: #装饰器私有化,批量重复使用 def __check_num_zsq(func): def inner(self,n): if not isinstance(n,int): raise TypeError("当前数据不是整型数值") return func(self,n) return inner #装饰器私有化,批量重复使用 def __say_zsq(func): def inner(self,n): #创建一个播报器对象 speaker = win32com.client.Dispatch("SAPI.SpVoice") #通过这个播报器对象,直接播放相对应的语音字符就可以了 speaker.Speak(n) return func(self,n) #函数返回值 return inner @__check_num_zsq @__say_zsq def __init__(self,num): #使用私有实例对象属性,防止变量污染 self.__result = num @__check_num_zsq @__say_zsq def jia(self,n): self.__result +=n @__check_num_zsq @__say_zsq def jian(self,n): self.__result -=n def multi(self,n): self.__result *=n def shows(self): print("计算的结果是:%d"%self.__result) c1 = Calc(2) c1.jia(3) c1.jian(2) c1.multi(5) c1.shows()
上述代码中一个方法被多个装饰器装饰,并且想要语音播报根据不同的方法播报不同的内容,就需要指定不同类型的装饰器进行装饰,但是太冗余了,使用添加参数的装饰器更加简便
import win32com.client class Calc: #装饰器私有化,批量重复使用 def __check_num_zsq(func): def inner(self,n): if not isinstance(n,int): raise TypeError("当前数据不是整型数值") return func(self,n) return inner #装饰器私有化,批量重复使用 def create_say_zsq(word=""): '''传入参数word''' def __say_zsq(func): #========此部分就是重写函数方法==== def inner(self,n): #创建一个播报器对象 speaker = win32com.client.Dispatch("SAPI.SpVoice") #通过这个播报器对象,直接播放相对应的语音字符就可以了 speaker.Speak(word+str(n)) return func(self,n) #函数返回值 return inner #将函数返回给装饰器 #========此部分就是重写函数方法==== return __say_zsq #再把装饰器返回给带参数的装饰器 @__check_num_zsq @create_say_zsq() def __init__(self,num): #使用私有实例对象属性,防止变量污染 self.__result = num @__check_num_zsq @create_say_zsq("加") def jia(self,n): self.__result +=n @__check_num_zsq @create_say_zsq("减") def jian(self,n): self.__result -=n @__check_num_zsq @create_say_zsq("乘") def multi(self,n): self.__result *=n def shows(self): print("计算的结果是:%d"%self.__result) c1 = Calc(2) c1.jia(3) c1.jian(2) c1.multi(5) c1.shows()
优化代码,共用一个方法__say()使代码具有维护性
import win32com.client class Calc: def __say(self,word): #创建一个播报器对象 speaker = win32com.client.Dispatch("SAPI.SpVoice") #通过这个播报器对象,直接播放相对应的语音字符就可以了 speaker.Speak(word) #装饰器私有化,批量重复使用 def __check_num_zsq(func): def inner(self,n): if not isinstance(n,int): raise TypeError("当前数据不是整型数值") return func(self,n) return inner #装饰器私有化,批量重复使用 def create_say_zsq(word=""): '''传入参数word''' def __say_zsq(func): #========此部分就是重写函数方法==== def inner(self,n): self.__say(word+str(n)) return func(self,n) #函数返回值 return inner #将函数返回给装饰器 #========此部分就是重写函数方法==== return __say_zsq #再把装饰器返回给带参数的装饰器 @__check_num_zsq @create_say_zsq() def __init__(self,num): #使用私有实例对象属性,防止变量污染 self.__result = num @__check_num_zsq @create_say_zsq("加") def jia(self,n): self.__result +=n @__check_num_zsq @create_say_zsq("减") def jian(self,n): self.__result -=n @__check_num_zsq @create_say_zsq("乘") def multi(self,n): self.__result *=n def shows(self): self.__say("计算的结果是:%d"%self.__result) print("计算的结果是:%d"%self.__result) c1 = Calc(2) c1.jia(3) c1.jian(2) c1.multi(5) c1.shows()
import win32com.client class Calc: def __say(self,word): #创建一个播报器对象 speaker = win32com.client.Dispatch("SAPI.SpVoice") #通过这个播报器对象,直接播放相对应的语音字符就可以了 speaker.Speak(word) #装饰器私有化,批量重复使用 def __check_num_zsq(func): def inner(self,n): if not isinstance(n,int): raise TypeError("当前数据不是整型数值") return func(self,n) return inner #装饰器私有化,批量重复使用 def create_say_zsq(word=""): '''传入参数word''' def __say_zsq(func): #========此部分就是重写函数方法==== def inner(self,n): self.__say(word+str(n)) return func(self,n) #函数返回值 return inner #将函数返回给装饰器 #========此部分就是重写函数方法==== return __say_zsq #再把装饰器返回给带参数的装饰器 @__check_num_zsq @create_say_zsq() def __init__(self,num): #使用私有实例对象属性,防止变量污染 self.__result = num @__check_num_zsq @create_say_zsq("加") def jia(self,n): self.__result +=n @__check_num_zsq @create_say_zsq("减") def jian(self,n): self.__result -=n @__check_num_zsq @create_say_zsq("乘") def multi(self,n): self.__result *=n def shows(self): self.__say("计算的结果是:%d"%self.__result) print("计算的结果是:%d"%self.__result) @property #使用描述器访问方法与访问属性相同,并且无法修改私有属性 def result(self): return self.__result c1 = Calc(2) c1.jia(3) c1.jian(2) c1.multi(5) c1.shows() print(c1.result)
使用链式编程的方法继续优化代码
import win32com.client class Calc: def __say(self,word): #创建一个播报器对象 speaker = win32com.client.Dispatch("SAPI.SpVoice") #通过这个播报器对象,直接播放相对应的语音字符就可以了 speaker.Speak(word) #装饰器私有化,批量重复使用 def __check_num_zsq(func): def inner(self,n): if not isinstance(n,int): raise TypeError("当前数据不是整型数值") return func(self,n) return inner #装饰器私有化,批量重复使用 def create_say_zsq(word=""): '''传入参数word''' def __say_zsq(func): #========此部分就是重写函数方法==== def inner(self,n): self.__say(word+str(n)) return func(self,n) #函数返回值 return inner #将函数返回给装饰器 #========此部分就是重写函数方法==== return __say_zsq #再把装饰器返回给带参数的装饰器 @__check_num_zsq @create_say_zsq() def __init__(self,num): #使用私有实例对象属性,防止变量污染 self.__result = num @__check_num_zsq @create_say_zsq("加") def jia(self,n): self.__result +=n return self #返回对象本身 @__check_num_zsq @create_say_zsq("减") def jian(self,n): self.__result -=n return self #返回对象本身 @__check_num_zsq @create_say_zsq("乘") def multi(self,n): self.__result *=n return self #返回对象本身 def shows(self): self.__say("计算的结果是:%d"%self.__result) print("计算的结果是:%d"%self.__result) return self #返回对象本身 @property #使用描述器访问方法与访问属性相同,并且无法修改私有属性 def result(self): return self.__result c1 = Calc(2) c1.jia(3).jian(2).multi(5).shows()
M54

浙公网安备 33010602011771号