【二十四】Python全栈之路--装饰器

本文详细介绍了Python装饰器的使用,包括无参数、有参数、嵌套、带有返回值的装饰器,以及类装饰器的应用。通过实例展示了如何在不修改原函数的情况下扩展其功能,如日志记录、权限验证等。同时,文章还探讨了装饰器的执行流程,并提供了类方法的相关知识,如普通方法、绑定方法和静态方法的调用。最后,给出了两个装饰器应用的实战例子,一个是实现认证功能,另一个是记录函数调用日志。
摘要由CSDN通过智能技术生成

1. 装饰器

# ### 装饰器 : 在不改变原有代码的前提下,为原函数扩展新功能
"""
@符号 装饰器的标识符 :
	(1) 自动把下面修饰的原函数当成参数传递给装饰器
	(2) 把返回的新函数去替换原函数
"""

# (1) 装饰器的原型

def kuozhan(_func):
	def newfunc():
		print("厕所前 ... 干净整齐")
		_func()
		print("厕所后 ... 臭气熏天")
	return newfunc

def func():
	print("我是屌丝...")
	
func = kuozhan(func) # func = newfunc   func() <=> newfunc()
func()


# (2) @符号的使用
print("<=======================>")
def kuozhan(_func):
	def newfunc():
		print("厕所前 ... 干净整齐")
		_func()		
		print("厕所后 ... 臭气熏天")
	return newfunc
	
@kuozhan
def func():
	print("我是高富帅...")

func()

# (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) 带有参数的装饰器
"""原函数和新函数的参数和返回值要保持一一对应"""
print("<===================>")
def kuozhan(_func):
	def newfunc(who,where,eat):
		print("厕所前 ... 文质彬彬")
		_func(who,where,eat)
		print("厕所后 ... 兽性大发")
	return newfunc

@kuozhan
def func(who,where,eat):
	print("{who}在{where}吃{eat}".format(who=who,where=where,eat=eat)  )
	
func("假率先","浴缸","榴莲") # <=> newfunc()

# (5) 带有参数返回值的装饰器
print("<=====>")

def kuozhan(_func):
	def newfunc(*args,**kwargs):
		print("手工耿同学向下面拉屎的同学们致敬 ~")
		res = _func(*args,**kwargs)
		print("请使用我的自动便便称重器 ... ")
		return res
		
	return newfunc
	
@kuozhan
def func(*args,**kwargs):	
	dic = {"liuwenbo":"刘文波","zhanglei":"张磊","songjian":"宋健"}
	lst = []
	try:
		i = 0
		for k,v in kwargs.items():
			# 键在dic中,再去拼凑字符串
			if k in dic:
				# 人名 + 地点 + 拉的重量
				strvar  = dic[k] + "在" + args[i] + "拉了" + v
				lst.append(strvar)
				i += 1	
	except:
		# print(i) # 2
		# print(list(dic.values())) # ['刘文波', '张磊', '宋健']
		# print(list(dic.values())[i])
		print("{}找不到拉屎的地点而错,请传入他的拉屎地点".format(list(dic.values())[i]))
		
		
	return lst	
	# return ["刘文博在电线杆子下面拉了15吨" , "张磊拉了15斤","宋健拉了15克"]

res = func("电线杆子下面","电影院",liuwenbo="15吨",zhanglei="15斤",songjian="15克")
print(res)


# (6) 使用类装饰器

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

print("<===============>")

# 方式二
@Kuozhan()
def func():
	print("厕所进行时 .... ")

func()


# (7) 带有参数的函数装饰器
def outer(num):

	def kuozhan(_func):
	
		def newfunc1(self):
			print(self)
			print("厕所前 ... 老实巴交")
			_func(self)
			print("厕所后 ... 浑身哆嗦")
			
		def newfunc2(self):
			print(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)  # (1)@outer(1) => @kuozhan  (2)@kuozhan =>  func1 = newfunc1 => (3) obj.func1() <=> obj.newfunc1(self)
	def func1(self):
		print("向前一小步,文明一大步")
		
	@outer(2)
	def func2(self):
		print("不冲就打包带走")

	@outer(3)
	def func3(self):
		print("请瞄准后发射,尿到外边,说明你短!")

print("<==============>")
obj = MyClass()
obj.func1() # <=> obj.newfunc1()

# print("<==============>")
# obj.func2()
# print("<==============>")
# print(obj.func3)



# (8) 带有参数的类装饰器
"""
参数1: 给修饰的类添加成员属性和方法
参数2: 把类中的run方法变成属性
"""

class Kuozhan():

	ad = "贵族茅厕,茅厕中的百岁山."
	
	def money(self):
		print("贵族茅厕,包月1100,一小时200元")
		
	def __init__(self,num):
		self.num = num
		
	def __call__(self,cls):
		print(cls) # MyClass
		if self.num == 1:
			return self.kuozhan1(cls)
		elif self.num == 2:
			return self.kuozhan2(cls)
			
	# 参数1的情况 : 添加成员属性和方法
	def kuozhan1(self,cls):
		def newfunc():
			# MyClass.ad = "贵族茅厕,茅厕中的百岁山."
			cls.ad = Kuozhan.ad
			cls.money = Kuozhan.money
			return cls()			
		return newfunc
		
	# 参数2的情况 : 把方法变成属性;
	def kuozhan2(self,cls):
		def newfunc():
			if "run" in cls.__dict__:
				cls.run = cls.run()
				return cls()
		return newfunc
		

	
print("<==================>")
# 方式一
"""
@Kuozhan(1) # => @obj => MyClass = obj(MyClass)
class MyClass():
	def run():
		return "亢龙有悔"

obj = MyClass()
print(obj.ad)
obj.money()
"""
# 方式二
@Kuozhan(2)
class MyClass():
	def run():
		return "亢龙有悔"
obj = MyClass()
print(obj.run)




"""
# (扩展)
虽然MyClass2这个名字替换掉了,但是内存中的该类仍然存在;
class MyClass2():
	a = 200

print(id(MyClass2) , "1111111")

def func(cls):
	cls.ad = 90
	print(id(cls),"22222")
	return cls()
obj = func(MyClass2)

MyClass2 = 100
print(MyClass2)
print(obj.a)  # 200 
print(obj.ad) # 90
"""

装饰器执行流程:
在这里插入图片描述
装饰器@符号使用:
在这里插入图片描述
第五步:
在这里插入图片描述
第六步:
在这里插入图片描述
第七步:
在这里插入图片描述
第八步:
在这里插入图片描述
在这里插入图片描述

2. 类中相关方法

# ### 类中相关方法
"""
(1)普通无参方法
(2)绑定方法: (1)绑定到对象 (2)绑定到类
(3)静态方法:无论是对象还是类调用静态方法,都不会默认传递任何参数
"""
class Dog():
	
	# 普通无参方法
	def tail():
		print("小狗喜欢摇尾巴")
	
	# 绑定到对象的方法
	def wang(self):
		print("小狗看到陌生人就叫")
		
	# 绑定到类的方法	
	@classmethod	
	def tian(cls):
		print(cls)
		print("小狗喜欢舔骨头")
		
	# 静态方法
	@staticmethod
	def jump(something):
		print("小狗喜欢接{}".format(something))
	
obj = Dog()
# 无参方法的调用
# obj.tail() #error
Dog.tail() #success


# 绑定到对象方法调用
obj.wang()
Dog.wang(obj)

# 绑定到类方法调用
"""无论对象还是类都可以调用,默认传递的是类"""
Dog.tian()
obj.tian()
print(obj.__class__)

obj.jump("飞盘")
Dog.jump("飞盘")

3. 小练习

"""
1.编写装饰器,为多个函数加上认证的功能(用户的账号密码)
要求只要登录成功一次,后续的函数都无需输入用户名和密码
"""

# 方法一
flag = False
def login(func):
	def inner(*args,**kwargs):
		global flag
		
		# 如果flag = True  代表已经登录
		if flag:
			res = func(*args,**kwargs)
			return res
			
		# 否则没有登录
		else:
			username = input("请输入您的用户名:")
			password = input("请输入您的密码")
			if username == "wangwen" and password == "111":
				# 登录成功
				flag = True
				res = func(*args,**kwargs)
				return res
			else:
				print("抱歉,账号或者密码输入错误~")
	return inner

@login
def buy_bao():
	print("我要买包")
	
@login
def buy_fruit():
	print("我要买水果")
	

# buy_bao()
# buy_fruit()


# 方法二
class Shopping():

	def __init__(self):
		self.flag = False

	# 装饰器
	def login(func):
		def inner(self,*args,**kwargs):
			
			
			# 如果flag = True  代表已经登录
			if self.flag:
				res = func(self,*args,**kwargs)
				return res
				
			# 否则没有登录
			else:
				username = input("请输入您的用户名:")
				password = input("请输入您的密码")
				if username == "wangwen" and password == "111":
					# 登录成功
					self.flag = True
					res = func(self,*args,**kwargs)
					return res
				else:
					print("抱歉,账号或者密码输入错误~")
		return inner

	@login
	def buy_bao(self,a):
		print("我要买包",a)
		
	@login
	def buy_fruit(self):
		print("我要买水果")
		
# obj = Shopping()
# obj.buy_bao(111111)
# obj.buy_fruit()
		
		
"""
2.编写装饰器,为多个函数加上记录调用功能,
要求 每次调用函数把调用的函数名称写入文件
"""

def log(func):
	def inner(*args,**kwargs):
		with open("log",mode="a",encoding="utf-8") as fp:
			fp.write( func.__name__ + "\n")
		res = func(*args,**kwargs)
		return res
	return inner

@log
def buy_bao():
	print("我要买包")

@log
def buy_fruit():
	print("我要买水果")


# print(buy_bao.__name__)
buy_bao()
buy_fruit()


  • 8
    点赞
  • 67
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值