Python(IT峰)笔记12-装饰器概念,装饰器的原型,装饰器的嵌套,装饰带有参数的函数,装饰器的嵌套,装饰带有多参数的函数,带有参数的装饰器,用类方法装饰函数,用韩式装饰器装饰类,用类装饰器装饰类

1、装饰器decorator概念
  • 在不改变原有函数代码,且保持原函数调用方法的基础上,给原函数增加新的功能(给类增加属性或方法)
  • 用一个函数或类去装饰一个旧函数(或类)造出一个新函数(或新类)
  • 在原有的函数上加上@符,装饰器会吧线面的函数当作参数传递到装饰器中,@符又称之为语法糖
  • 应用场景:引入日志,函数执行时间统计,执行函数前的准备工作,执行函数后的处理工作,权限校验缓存等
2、装饰器的原型

描述器扩展属性,装饰器扩展方法(这句弹幕里看到的)
利用闭包,把函数当作参数传递,并且在函数内去调用传递进来的函数,并返回一个函数

传统用法

#定义一个闭包函数(外函数),有一个f形参,作为要向这个参数传递的参数
def outer(f):
	#定义内函数,并在内函数中调用了外函数的参数
	def inner():
		print('我是外函数中的内函数1')
		f()
		print('我是外函数中的内函数2')
	return inner


#定义一个普通的函数
def old():
	print('我是一个普通函数')

old=outer(old)#outer返回了inner函数,赋值给了old
old()#实际调用的是inner函数

结果是:

我是外函数中的内函数1
我是一个普通函数
我是外函数中的内函数2

装饰器用法

#定义一个闭包函数(外函数),有一个f形参,作为要向这个参数传递的参数
def outer(f):
	#定义内函数,并在内函数中调用了外函数的参数
	def inner():
		print('我是外函数中的内函数1')
		f()
		print('我是外函数中的内函数2')
	return inner


#定义一个普通的函数
#增加装饰符
@outer#实际就是把old装进了outer,old函数作为outer函数的实参传给了outer
def old():
	print('我是一个普通函数')
old()#实际调用的是inner函数

结果是:

我是外函数中的内函数1
我是一个普通函数
我是外函数中的内函数2
3、案例-统计函数执行时间
#装饰器应用场景-统计函数执行时间
import time

#定义一个统计函数执行时间的装饰器
def runtime(func):
	def inner():
		start=time.perf_counter()
		func()
		end=time.perf_counter()-start
		print(f'函数的调用执行时间为:{end}')
	return inner
@runtime
def func():
	for item in range(1,10):
		print(item,end=' ')
		time.sleep(0.5)

func()#1 2 3 4 5 6 7 8 9 函数的调用执行时间为:4.504389300000001
4、装饰器的嵌套

1、先使用离得近的outer装饰器,装饰love函数,返回了一个inner函数
2、再使用上面的扩展装饰器,装饰上一次返回的inner函数 ,有返回了kzinner函数

#外函数
def outer(func):
	def inner():
		print('find somebody to talk')
		func()
		print('talk with him at a place')
	return inner

#再定义一个装饰器
def kuozhan(func):
	def kzinner():
		print('扩展1')
		func()
		print('扩展2')
	return kzinner
#扩展的嵌套,这里装饰符的先后,决定了嵌套的顺序,进而决定了执行语句的顺序
@kuozhan
@outer
def love():
	print('falling love with somebody')

love()

结果为:

find somebody to talk
扩展1
falling love with somebody
扩展2
talk with him at a plac
5、装饰器带有参数的函数

如果装饰带有参数的函数,需要在内函数中定义形参,并传递给调用的函数,因为调用原函数等于调用内函数

#定义一个装饰器
def outer(func):
	#如果装饰带有参数的函数,需要在内函数中定义形参,并传递给调用的函数,因为调用原函数等于调用内函数
	def inner(person):
		print('找到一个人')
		func(person)
		print('找一个地方')
	return inner

#使用装饰器
@outer
def love(name):
	print(f'和{name}一起畅谈人生')

love('思思')
6、装饰带有多参数的的函数
# 定义一个装饰器
def outer(func):
	# 如果装饰带有参数的函数,需要在内函数中定义形参,并传递给调用的函数,因为调用原函数等于调用内函数
	def inner(who, name, *args, **kwargs):
		print('找到一个人')
		func(who, name, *args, **kwargs)
		print('找一个地方')

	return inner


# 使用装饰器
@outer
def love(who, name, *args, **kwargs):
	print(f'{who}{name}一起畅谈人生')
	print('然后去吃了好多美食', args)
	print('看了一场电影', kwargs)


love('思思','三多','火锅','辣条','麻辣烫',moive='速度与激情')

结果

找到一个人
思思和三多一起畅谈人生
然后去吃了好多美食 ('火锅', '辣条', '麻辣烫')
看了一场电影 {'moive': '速度与激情'}
找一个地方
7、带有参数的装饰器

如果装饰器需要有参数,那么应该给当前装饰器套个壳,用于接收装饰器的参数

# 定义一个装饰器
# 如果装饰器需要有参数,那么应该给当前装饰器套个壳,用于接收装饰器的参数
def kuozhan(person):
	def outer(func):
		def inner1():
			print('找到一个人')
			func()
			print('找一个地方')

		def inner2():
			print('找到另外的一个人')
			func()
			print('找一个也许还蛮有意思的地方')
		#装饰器壳的参数,用于在函数内去做流程控制
		if person == '高富帅':
			return inner1
		else:
			return inner2

	return outer


# 使用装饰器,装饰器带参
@kuozhan('高富帅')  # 使用套壳的装饰器名称
def love():
	print('一起畅谈人生')
love()
print('****')
@kuozhan('矮穷矬')  # 使用套壳的装饰器名称
def love():
	print('一起畅谈人生')
love()

结果:

找到一个人
一起畅谈人生
找一个地方
****
找到另外的一个人
一起畅谈人生
找一个也许还蛮有意思的地方
8、类装饰器装饰函数

Outer()得到一个obj @obj得到obj(love)然后再执行call(love)最后调用inner()

# 定义一个装饰器
class Outer():
	#当把该类的对象当作函数调用时,自动触发obj()
	def __call__(self, func):
		self.func=func#把传进来的函数当作对象的成员方法
		return  self.inner#返回一个闭包(函数)
	#在定义的需要返回的新方法中,去进行装饰和处理	
	def inner(self,person):
		print('找一个人')
		self.func(person)
		print('找一个地方')

# 使用装饰器
@Outer() #Outer()得到一个obj @obj得到obj(love)然后再执行call(love)最后调用inner()
def love(person):
	print(f'和{person}一起畅谈人生')
love('张三丰')#实际调用的事装饰器里的inner函数
print(love)#此时love就是Outer类中的inner方法。<bound method Outer.inner of <__main__.Outer object at 0x000001F4D7C4C460>>
9、用类方法装饰函数

到目前为止,所有的形式的装饰器,包括函数装饰器,类装饰器,类方法装饰器,都有一个共同特点:都是在给函数进行装饰,增加功能

还有一种装饰器,是专门装饰类的,也就是在类的定义的前面是用@装饰器这种语法

# 定义一个装饰器
class Outer():
	def newInner(func):
		Outer.func = func
		return Outer.inner
	def inner():
		print('找到一个人')
		Outer.func()
		print('约到一个地方')

# 使用装饰器
@Outer.newInner  # 使用Outer.newInner(love)==>Outer.inner
def love():
	print('和志同道合者一起畅谈人生')

love()#love()=>Outer.inner()
10、用函数装饰器装饰类

还有一种装饰器,是专门装饰类的,也就是在类的定义的前面是用@装饰器这种语法
装饰器给类装饰,目的是为了不改变类的定义和调用的情况下给类增加新的成员(属性或方法)

# 定义一个函数装饰器,给类增加新的属性和方法
def kuozhan(cls):
	def func2():
		print('我是在装饰器中追加扩展的新方法,func2')
	#把刚才定义的类赋值给类
	cls.func2=func2
	#再添加一个新属性
	cls.name='我是装装饰器添加的新属性name'

	#返回时,吧追加类新成员的类返回去
	return cls

#使用装饰器
@kuozhan
class Demo():
	def func():
		print(' 我是demo类中定义的func方法')


Demo.func()#此时调用的Demo类是通过装饰器修改过的类
Demo.func2()#装饰器新添加的方法
print(Demo.name)#装饰器新添加的属性

结果

 我是demo类中定义的func方法
我是在装饰器中追加扩展的新方法,func2
我是装装饰器添加的新属性name

11、用类装饰器装饰类
# 定义一个类装饰器,给类增加新的属性和方法
class kuozhan():
	def __call__(self, cls):
		#把接受的类,赋值给当前对象,作为一个属性
		self.cls=cls
		#返回一个函数
		return self.newFunc

	def newFunc(self):
		self.cls.name='我是在类装饰器中添加的属性name'
		self.cls.func2=self.func2
		#返回传递进来的实例化结果,obj,返回的是一个对象,self.cls(),因为self.cls是传进来的类

		return self.cls()

	def func2(self):
		print('我是在类装饰其中追加的方法func2')

#使用类装饰器
@kuozhan()#kuozhan()=》obj==》@obj(Demo)==》__call__(Demo)==>newfunc
class Demo():
	def func(self):
		print(' 我是demo类中定义的func方法')


obj=Demo()#Demo()=newFunc()==>obj
obj.func()
obj.func2()
print(obj.name)
print(obj)#此时的obj依然是Demo类的实例化对象,只不过经过装饰后,增加了新的属性和方法

结果

 我是demo类中定义的func方法
我是在类装饰其中追加的方法func2
我是在类装饰器中添加的属性name
<__main__.Demo object at 0x000001AFB370B400>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值