装饰器:为原函数去扩展新功能,用新函数去替换旧函数
作用:在不改变原代码的前提下,实现功能性扩展
符号(语法糖):@
一、装饰器的基本用法
先来看下面这段代码:
def extend(func):
def newfunc():
print("I have a pen")
func()
return newfunc
def func():
print("I have an apple")
func=extend(func)
func()
运行结果:
在上图中,使用闭包函数扩展了函数func的功能
@语法糖的使用:
1、可以自动把@下面的函数当成参数传递给装饰器
2、把新函数返回,让新函数替换旧函数,以实现功能上的扩展(基于原函数)
def extend(func):
def newfunc():
print("I have a pen")
func()
return newfunc
@extend
def func():
print("I have an apple")
func()
运行结果:
二、装饰器的嵌套
def extend1(func):
def newfunc1():
print("扩展start1")
func()
print("扩展end1")
return newfunc1
def extend2(func):
def newfunc2():
print("扩展start2")
func()
print("扩展end2")
return newfunc2
@extend2
@extend1
def func():
print("我是func函数")
func()
运行结果:
在上例中,首先将func传入extend1装饰器进行扩展,再将扩展后的函数覆盖原func,最后将新生成的函数传入装饰器extend2,得到最后结果。
三、用装饰器扩展带有参数的原函数
def extend(func):
def newfunc(who,where,do):
print("8月7日")
func(who,where,do)
print("end")
return newfunc
@extend #func=extend(func)
def func(who,where,do):
print("{}在{}{}".format(who,where,do))
func("Lsir","电影院","看电影")
运行结果:
四、用装饰器扩展带有参数和返回值的原函数
def extend(func):
#形参打包
def new_func(*args,**kwargs):
print("hobby:")
#实参解包
lst=func(*args,**kwargs)
print(lst)
print("end")
return new_func
@extend
def func(*args,**kwargs):
strvar=""
for n in kwargs:
strvar += kwargs[n]
for i in args:
strvar += i
return strvar
func("Lsir","在电影院","看电影",date="8月7日")
运行结果:
五、用类装饰器来拓展原函数
class MyClass():
def __call__(self,func):
return self.extend(func)
def extend(self,func):
def newfunc():
print("落华却看悲白发")
func()
return newfunc
@MyClass() #func=obj(func)
def func():
print("少时不识曲中天")
func()
运行结果:
@MyClass() 生成对象,相当于@obj,func=obj(func),触发call魔术方法,func传入MyClass类中,执行extend函数,return返回值覆盖func,func()实际执行newfunc().
六、带有参数的函数装饰器
def outer(num):
def extend(func):
def newfunc1(self):
print("8月5日")
func(self)
def newfunc2(self):
print("8月6日")
func(self)
def newfunc3(self):
print("8月7日")
func(self)
if num == 1:
return newfunc1
elif num == 2:
return newfunc2
elif num == 3:
return newfunc3
return extend
class MyClass():
@outer(1)
def func1(self):
print("Lsir在电影院")
@outer(2)
def func2(self):
print("Lsir在机场")
@outer(3)
def func3(self):
print("Lsir在公司")
obj=MyClass()
obj.func1()
obj.func2()
obj.func3()
运行结果:
七、带有参数的类装饰器
class Extend():
car="特斯拉"
def __init__(self,num):
self.num=num
def __call__(self,cls):
if self.num == 1:
return self.moudle1(cls)
elif self.num == 2:
return self.moudle2(cls)
def oil(self):
print("油耗3.0")
def moudle1(self,cls):
def newfunc():
cls.car=Extend.car
cls.oil=Extend.oil
return cls()
return newfunc
def moudle2(self,cls):
def newfunc():
if "func" in cls.__dict__:
res=cls.func(self)
cls.func=res
return cls()
return newfunc
@Extend(1)
class MyClass():
def func(self):
return "时速百公里"
obj = MyClass()
print(obj.car)
obj.oil()
@Extend(2)
class MyClass():
def func(self):
return "时速百公里"
obj = MyClass()
print(obj.func)
运行结果:
分析:
以参数1为例
参数为1,代码解析:
@Extend(1) => @obj => @符第一次发动技能:
把MyClass当成参数传递给obj => obj(MyClass) => return self.moudle1(cls) => return newfunc
@obj => @符第二次发动技能:
实现替换效果,将 MyClass = newfunc
obj = MyClass() = newfunc() = cls() = 对象
对象.属性 obj.car
对象.方法 obj.oil()