装饰器:在不改变原有代码的情况下,为该原函数扩展新功能
特征:返回新函数,替换旧函数
语法:@ 语法糖
1.装饰器原型
#例1:
def kuozhan(func):
def newfunc():
print("吃饭前,无精打采")
func()
print("吃饭后,精神百倍")
return newfunc
def func():
print("我是个吃货")
#手动的 把新函数 赋值 给 旧函数
func = kuozhan(func)
func()
2.装饰器 @
#例 2:
print("=====例2=====")
def kuozhan(func):
def newfunc():
print("吃饭前,无精打采")
func()
print("吃饭后,精神百倍")
return newfunc
@kuozhan
def func():
print("我是个吃货")
func()
print("=================")
步骤解析:
第一步:先把下面的func当成参数传递给kuozhan
第二步:把返回的新函数重新赋值给func
* 谁跟在@ 这个装饰器的下面,就会自动把谁当成参数传递
func = kuozhan(func)
3.互相嵌套的装饰器函数
#例3:
def kuozhan1(func):
def newfunc():
print("吃饭前前,化化妆1")
func()
print("吃饭后,补补妆2")
return newfunc
def kuozhan2(func):
def newfunc():
print("吃饭前,洗洗手3")
func()
print("吃饭后,簌簌口4")
return newfunc
@kuozhan2
@kuozhan1
def func():
print("我是一个白富美5")
func() #3 1 5 2 4
4.带有参数的装饰器
原函数在扩展之前是几个参数,那么扩展之后也相应有几个参数
#例4:
def kuozhan(func):
def newfunc(who,where):
print("开饭前,安安静静")
func(who,where)
print("开饭后,热热闹闹")
return newfunc
@kuozhan
def func(who,where):
print("{}进{}吃饭".format(who,where))
func("one","食堂")
5.带有参数返回值的装饰器
'''通过装饰器改造之后,原函数返回什么,新函数返回什么'''
print("=================")
#例5:
def kuozhan(func):
def newfunc(*args, **kwargs):
print("留下之前")
res = func(*args, **kwargs)
print("留下之后")
return res
return newfunc
@kuozhan
def func(*args, **kwargs):
print(args)
for i in args:
print("藏东西的地点:", i)
dic = {'p1': "one", "p2": "two"}
'''
#法一:for循环再将元素加入列表得到:
lst = []
for k,v in dic.items():
#如果k在dic这个字典里,说明这个字典存在这个键,然后我就通过键取值
if k in dic:
lst.append("{}留下了黄金{}".format(dic[k],v))
'''
#法二:推导式方法得出:
lst = ["{}留下了黄金{}".format(dic[k], v) for k, v in kwargs.items() if k in dic]
return lst
res = func("电影院", "游泳池", p1="15克", p2="150克")
print("=================")
print(res)
print("=================")
回忆以前的知识点:
* 和 ** 的魔术方法(函数调用处)
#例:
def func(a,b,c):
print(a,b,c)
func(*[1,2,3])
def func(a=1,b=2,c=3,*,d=4):
print(a,b,c)
func(**{"a":3,"b":4,"c":5,"d":6})
6.用装饰器修饰原函数
#例6:
class MyClass():
def __call__(self,func):
#pass
return self.kuozhan2(func)
def kuozhan1(func):
def newfunc():
print("酒店前,饥肠辘辘")
func()
print("酒店后,酒足饭饱")
return newfunc
def kuozhan2(self,func):
def newfunc():
print("酒店前,茶饭不思")
func()
print("酒店后,大肚偏偏")
return newfunc
#方法一
@MyClass.kuozhan1
def func():
print("吃饭进行时... ....")
func()
#方法二:
@MyClass()
def func():
print("吃饭进行时... ...")
func()
#代码解析:
先把 @ 符号右边的值算出来,在通过 @ 符号把下面的函数当成参数进行传递
@MyClass() 就相当于 @obj
把func当成参数传递给obj => obj(func)
obj 当成一个函数再进行调用,自动触发__call__魔术方法
return newfunc
func = newfunc
func() 就相当于 newfunc()
7.带有参数的函数装饰器
#例7:
def outer(num):
def kuozhan(func):
def newfunc1(self):
print("人前,老实巴交")
func(self)
print("人后,张牙舞爪")
def newfunc2(self):
print("人前,衣冠楚楚")
func(self)
print("人后,衣冠禽兽")
if num == 1:
return newfunc1
elif num == 2:
return newfunc2
elif num == 3:
return "今天天气好晴朗哦"
return kuozhan
class MyClass():
@outer(1)
def func1(self):
print("走一步")
@outer(2)
def func2(self):
print("再走一步")
@outer(3)
def func3(self):
print("换个角度想想")
print("=================")
obj = MyClass()
obj.func1()
print("=================")
obj.func2()
print("=================")
print(obj.func3)
#代码解析:
outer(1) => 返回kuozhan 函数
@kuozhan
func1
@符号开始发挥作用
把func1当成参数进行传递,传给kuozhan中的func进行接收
obj.func1 = newfunc1
obj.func1() <====>newfunc1
@outer(3) => 返回kuozhan 函数
@kuozhan
func3
@符号开始发挥作用
把func3当成参数进行传递,传给kuozhan中的func进行接收
obj.func3 = "今天天气好晴朗哦"
print(该值) [因为函数名可以作为变量使用]
8.带有参数的类装饰器
如果传递的参数是1 ,我就为该类,添加成员属性和方法
如果传递的参数是2,我就把该类当中的run方法变成属性
#例8:
class KuoZhan():
ad = "高档餐厅,欢迎您来,欢迎您再来"
def __init__(self,num):
self.num = num
def __call__(self,cls):
if self.num == 1:
return self.kuozhan1(cls) #newfunc 返回
elif self.num == 2:
return self.kuozhan2(cls)
def money(self):
print("收费标准,最低消费每人500")
def kuozhan1(self,cls):
def newfunc():
#添加成员属性
cls.ad = KuoZhan.ad
#添加成员方法
cls.money = KuoZhan.money
return cls()
return newfunc
def kuozhan2(self,cls):
def newfunc():
#先判断run方法是否在cls当中
if "run" in cls.__dict__:
#调用一个类中得run方法拿到返回值"亢龙有悔"
res = cls.run()
#成员属性run从方法变成属性,值替换了
cls.run = res #把"亢龙有悔" 进行替换赋值给run成员属性
return cls()
return newfunc
@KuoZhan(1) # @obj = > obj(MyClass)
class MyClass():
def run():
return "亢龙有悔"
obj = MyClass()
print(obj.ad)
obj.money()
"""
#代码解析:
KanZhan(1) => obj 自动触发init方法 ,存储num => self.num = num
@obj
@符发挥作用把MyClass 当成一个参数传递给obj => obj(MyClass)
触发__call__ 魔术方法,最后将newfunc进行返回
MyClass = newfunc 以前是类 现在是函数
obj = MyClass <========> newfunc()
obj = cls() #cls() 是一个对象,是以前MyClass 这个类的对象
"""
@KuoZhan(2)
class MyClass():
def run():
return "亢龙有悔"
obj = MyClass()
print(obj.run)
print("=====================================")
#外面全局的abc 与函数内部局部的 abc 两者不发生冲突,彼此独立
class abc():
a = 19
def func(cls):
cls.b = 20
return cls
obj2 = func(abc)
print(abc().a)
abc = 68970
print(abc)
print(obj2.b)
print(obj2.a)