装饰器★★★★★★

本文详细介绍了Python装饰器的使用,包括基本用法、@符号的含义、装饰器的嵌套以及如何通过扩展函数和类为原函数和类添加新功能,特别是如何处理带参数的函数和类成员。重点讨论了如何利用闭包保持状态,并通过装饰器实现方法到属性的转换。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

### 装饰器(运用了闭包函数)

"""
装饰器: 为原函数扩展新功能,用新功能去替代旧功能
作用  : 在不改变原有代码的基础上,实现功能上的扩展
符号  : @(语法糖)

"""

1.装饰器的基本用法

def kuozhan(func):
	def newfunc():
		print("厕所前,蓬头垢面")
		func()
		print("厕所后,精神气爽")
	return newfunc

def func():
	print("我叫高富帅")

func = kuozhan(func) # func = newfunc  <=>   func() = newfunc()
func()

2.@符号的使用

"""
@符号作用: 
	(1) 可以自动把@符号下面的函数当成参数传递给装饰器
	(2) 把新函数进行返回,让新函数去替换旧函数,以实现功能的扩展.		
"""
def kuozhan(func):
	def newfunc():
		print("厕所前,蓬头垢面")
		func()
		print("厕所后,精神气爽")
	return newfunc

@kuozhan
def func():
	print("我叫高富帅")

func()  # func = newfunc  <=>   func() = newfunc()

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()

4.用扩展函数添加带有参数的原函数的新功能

"""扩展里面的新功能函数和原函数在参数和函数调用处的参数上,要保持一致性."""
def kuozhan(func):
	def newfunc(who,where):
		print("厕所前,萎靡不振")
		func(who,where)
		print("厕所后,兽性大发")
	return newfunc

@kuozhan
def func(who,where):
	print("{who}在{where}解手".format(who=who,where=where))

func("朱胜","电影院")

5.用扩展函数添加带有参数返回值的原函数的新功能★★★★★

"""扩展函数里面的新功能函数和原函数在参数和返回值(return)上,要保持一致性."""
#如果原函数有返回值,在扩展里面的新函数中调用处的函数也要赋予变量接收,用return 返回变量
#函数装饰函数,扩展函数里面添加新的函数返回
#如果原函数没有return  ,新函数可加可不加,加上没有返回None

def kuozhan(func):
	def newfunc(*args,**kwargs): # 函数的定义处, *号的打包操作
		print("厕所前,饥肠辘辘")
		lst = func(*args,**kwargs) # 函数的调用处,*号解包操作
		print("厕所后,酒足饭饱")
		return lst
	return newfunc
@kuozhan
def func(*args,**kwargs):
	dic = {"wz":"王振" , "wyl":"尉翼麟" , "yc":"云超"}
	lst = []
	strvar = ""

	# 遍历拉屎的地点
	for i in args:
		print("拉屎的地方在", i )

	"""
	# 正常写法
	for k,v in kwargs.items():	
		if k in dic:
			strvar = dic[k] + "留下" + v + "黄金"
			lst.append(strvar)
	return lst
	"""
	# 推导式
	return [dic[k] + "留下" + v + "黄金" for k,v in kwargs.items() if k in dic]

res = func("电影院","水里",wz="18斤",wyl="18吨",yc="18克",zzz = "19k")
print(res)

6.用类去添加原函数新功能★★★★★

#先把类当做对象(类加括号就是对象),@会把原函数当做参数传递给类对象,类对象就会触发call,为了使类对象和call参数一一对应,call也会接收一个func,通过call来调取扩展函数(有参要带参数,且要与call对应,除了self以外的参数,self用来调用,调用的扩展函数中也要有),通过return 返回,间接得到里面的新功能函数(相当于在函数装饰函数外面套了一个类的外壳)
class Kuozhan():

	def __call__(self,func):
		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
	
"""方法一
@Kuozhan.kuozhan1
def func():==>原函数
	print("厕所进行时...")
func()
"""

方法二 (推荐)
@Kuozhan()
def func():  ==>原函数
	print("厕所进行时...")
func()
解释:
@Kuozhan()  => @obj<=>对象 => obj(func) <=> 把对象当成函数进行使用了,	自动触发__call__魔术方法. 
=>  把新函数newfunc 返回了  => @ 发动第二个技能,将新函数去替换旧函数, func = newfunc
func()  <==>  newfunc()

7.用带有参数的函数添加类成员功能★★★★★

def outer(num):
	def kuozhan(func):
		def newfunc1(self):
			print("厕所前,干净整齐")
			res = func(self)
			print("厕所后,臭气熏天")
			return res
		
		def newfunc2(self):
			print("厕所前,饥肠辘辘")
			res = func(self)
			print("厕所后,满口雌黄")
			return res

		if num == 1 :
			return newfunc1			
		elif num == 2:
			return newfunc2
		elif num == 3:
			# 把方法变成属性★★★★★★
			return "我是男性"			
		
	return kuozhan


class MyClass():
	@outer(1) # outer(1) => kuozhan  ,   @kuozhan <=> kuozhan(func1) [@符号第一次发动技能] <=> func1 = newfunc1 [@符号第二次发动技能]
	def func1(self):
		print("先前一小步,文明一大步")
	
	@outer(2) # outer(2) => kuozhan  ,   @kuozhan <=> kuozhan(func2) [@符号第一次发动技能] <=> func2 = newfunc2 [@符号第二次发动技能]
	def func2(self):
		print("来也匆匆,去也匆匆")

	@outer(3) # outer(3) => kuozhan  ,   @kuozhan <=> kuozhan(func3) [@符号第一次发动技能] <=> func3 = "我是男性"
	def func3():
		print("尿到外面,说明你短!")

obj = MyClass()
obj.func1() # func1 <=> newfunc1
obj.func2()
把方法变成属性
print(obj.func3)

8.用带有参数的类添加原类功能★★★★★

类加括号是对象,括号中有值是初始化,一定有init接收值
"""
如果参数是1,就为当前类添加成员属性和方法
如果参数是2,就把原方法run变成属性
"""
class Kuozhan():
	ad = "贵族茅房,每小时100元,贵族茅房,欢迎您来,欢迎您再来"
	def __init__(self,num):
		self.num = num
	
	def __call__(self,cls):
		if self.num == 1:
			return self.newfunc1(cls)
		elif self.num == 2:
			return self.newfunc2(cls)
		
	def money(self):
	print("茅中贵族,百岁山")
	
# 参数为1的情况
	def newfunc1(self,cls):
		def newfunc():
			# 为当前cls这个类,添加属性
			cls.ad = Kuozhan.ad
			# 为当前cls这个类,添加方法
			cls.money = Kuozhan.money
			return cls()  # 对象
		return newfunc
	
	# 参数为2的情况
	def newfunc2(self,cls):
		def newfunc():
			if "run" in cls.__dict__:
				# 调用类中的方法,拿到返回值
				res = cls.run()
				# 把返回值重新赋值给run属性.后者覆盖了前者,方法变成了属性
				cls.run = res
				return cls()
			
		return newfunc

 obj = Kuozhan(1)
 
@obj  [@符号第一次发动技能] <=> obj(MyClass) 把对象当成函数使用了,触发__call__魔术方法
self.newfunc1(cls) <=> return newfunc 
=>  [@符号第二次发动技能]  将新函数替换旧函数 MyClass = newfunc  
obj = MyClass()  <=> newfunc() => cls() => obj对象
"""
情况一
"""
@Kuozhan(1) 
class MyClass():
	def run():
		return "亢龙有悔"

obj = MyClass()
print(obj.ad)
obj.money()
"""

""
@obj  [@符号第一次发动技能] <=> obj(MyClass) 把对象当成函数使用了,触发__call__魔术方法
self.newfunc2(cls) <=> return newfunc 
=>  [@符号第二次发动技能]  将新函数替换旧函数 MyClass = newfunc  
obj = MyClass()  <=> newfunc() => cls() => obj对象
"""
情况二
@Kuozhan(2) 
class MyClass():
	def run():
		return "亢龙有悔"
obj = MyClass()
print(obj.run) # 亢龙有悔

★★★★★★★
1:为原函数添加成员(装饰函数): @就在原函数的上面
用函数去添加:
(@函数,传进去的是一个函数变成参数,添加新成员时直接打印),扩展一个函数,把原函数当做参数放到扩展函数中,返回一个新函数,并且在新函数中调用扩展函数的参数,扩展函数把新函数返回出来.
用类去添加:要把类变成对象:
(@类(),传进去的是一个函数变成参数,添加新功能时直接打印)先把类变成对象,直接触发call,对象会把函数当做参数传递给call,call也会获得一个参数,一一对应,扩展一个函数,里面在创建新函数.添加新功能,并且调用扩展函数里面的参数,最后扩展函数将新函数返回,形参闭包,通过call来调取扩展函数间接得到新函数(新功能),相当于扩展一个函数,返回一个新函数,在扩展函数外面套一个类外壳,把原函数当做参数放到类对象( 类() )对象中,用call来触发,通过call调用扩展函数返回,间接得到新函数

2:为类成员(方法)添加成员(装饰类中成员):用函数去添加@就在原类成员的上面
(@函数,传进去的是一个函数变成参数,添加新功能时直接打印)因为类中成员(方法)比较多,添加类中的每一个成员(方法)功能时,例如@func(1),@func(2),先算@右侧func(1)里面的值,先定义一个外壳函数,把func1传到外壳函数中,外壳函数参数要与func参数一致,计算完以后,创建一个扩展函数,执行到扩展函数中,然后把类中的每一个函数当做一个参数传递到扩展函数,在扩展函数里面在创建多个新函数用序号标清,新函数要添加新成员并且调用扩展函数的参数(调用),为了保证原函数功能不缺失,然后通过外壳函数传进来的参数在扩展函数内部进行判断,然后返回(return)对应的新函数里面的成员,最后用这个外壳函数返回扩展函数,形成闭包,这样在新函数中的判断不会释放掉(相当于函数装饰函数外面在套一个外壳,这个外壳用来接收类中第几个方法,最后在实现新功能的添加)

3:为类添加成员,和修改原类成员方法变属性,用扩展类去添加 @就在原类上面
(@扩展类(),传进去的是一个类变成参数,添加新功能时用传进去的类添加),首先先把添加的属性和方法写到扩展类中,通过扩展类调用属性和方法赋值给传进来的类(类点属性或方法(自定义的属性和方法)=属性或方法,因为类添加的功能不只一个,例如;@class(1),先要算class(1),他是初始化参数为一,要用到init初始化,运行完以后再算@class这个对象,触发call,连同这个参数类也要传到call中,在扩展一个函数,里面在创建新函数.用传进来的类点(属性或者方法)==扩展类中调用的属性或者方法添加新功能,并且新函数要调用扩展函数的参数(在外函数返回新函数时,传进来的类变成了函数,可以调用),然后通过call的判断来返回(return)扩展函数,参数要一一对应,从而间接得到新函数(新功能),★★★★★修改原类成员方法变属性,首先判断方法是否在原类成员中(dict),然后调用原类中的方法,拿到返回值,把返回值重新赋值给run属性.后者覆盖了前者,方法变成了属性(原类点run=返回值)

#为类添加成员,要用扩展类实现,为类中的成员添加成员,用扩展函数
#为函数添加成员,用函数或者类
#为类中的成员或者类去添加成员,都要有判断
#通过把原函数当做参数传进时.要形成一个闭包
#如果原函数中有return,新函数调用扩展函数的参数时,也要变量接收,在return ,或者直接return
#在外部类添加方法时,用lambda表达式(类点自定义方法=lambda表达式)
#调用的时候要注意参数
#在扩展类中,传进来的参数类在添加扩展方法和属性时,直接对象点方法(自定义)等于方法 即: 类点自定义属性或者方法=扩展类.属性或者方法(不需要加括号和参数)
#@类(1)相当于先初始化,然后在相当于对象传参给call

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值