装饰器的使用,类装饰器,带有参数装饰器,多个装饰器,通用装饰器的使用

  1. 装饰器的定义
    就是给已有函数增加额外功能的函数,它本质上就是一个闭包函数。
    装饰器的功能特点:
    1. 不修改已有函数的源代码
    2. 不修改已有函数的调用方式
    3. 给已有函数增加额外的功能
  2. 装饰器的示例代码
# 添加⼀个登录验证的功能
def check(fn):
	def inner():
		print("请先登录....")
		fn()
	return inner


def comment():
	print("发表评论")
	# 使⽤装饰器来装饰函数
comment = check(comment)
comment()



# 装饰器的基本雏形
# def decorator(fn): # fn:⽬标函数.
#		 def inner():
#		 '''执⾏函数之前'''
# 				fn() # 执⾏被装饰的函数
# 	'''执⾏函数之后'''
# return inner

代码说明:

  • 闭包函数有且只有一个参数,必须是函数类型,这样定义的函数才是装饰器。
  • 写代码要遵循开放封闭原则,它规定已经实现的功能代码不允许被修改,但可以被扩展。

执行结果:


请先登录..
发表评论
  1. 装饰器的语法糖写法
    如果有多个函数都需要添加登录验证的功能,每次都需要编写func = check(func)这样代码对已有函数进
    行装饰,这种做法还是比较麻烦。
    Python给提供了一个装饰函数更加简单的写法,那就是语法糖,语法糖的书写格式是: @装饰器名字,通过语法糖的方式也可以完成对已有函数的装饰
# 添加⼀个登录验证的功能
def check(fn):
	print("装饰器函数执⾏了")
	def inner():
		print("请先登录....")
		fn()
	return inner
# 使⽤语法糖⽅式来装饰函数
@check
def comment():
	print("发表评论")
comment()

说明:

  • @check 等价于 comment = check(comment)
  • 装饰器的执行时间是加载模块时立即执行。

执行结果:、

请先登录....
发表评论

  • 小结
  • 装饰器本质上就是一个闭包函数,它可以对已有函数进行额外的功能扩展。
  • 装饰器的语法格式:
# 装饰器
# def decorator(fn): # fn:被装饰的⽬标函数.
# 		def inner():
#			 '''执⾏函数之前'''
#			 fn() # 执⾏被装饰的⽬标函数
#			 '''执⾏函数之后'''
# return inner

  • 装饰器的语法糖用法: @装饰器名称,同样可以完成对已有函数的装饰操作。

装饰器的使用
装饰器的使用场景:

  1. 函数执行时间的统计
  2. 输出日志信息

装饰器实现已有函数执行时间的统计

import time
# 装饰器函数
def get_time(func):
	def inner():
		begin = time.time()
		func()
		end = time.time()
		print("函数执⾏花费%f" % (end-begin))
	return inner

@get_time
def func1():
	for i in range(100000):
		print(i)

func1()

执行结果:

...
99995
99996
99997
99998
99999
函数执⾏花费0.329066

小结

通过上面的示例代码可以得知装饰器的作用:

  • 在不改变已有函数源代码及调用方式的前提下,对已有函数进行功能的扩展。

通用装饰器的使用

  1. 装饰带有参数的函数
# 添加输出⽇志的功能
def logging(fn):
	def inner(num1, num2):
		print("--正在努⼒计算--")
		fn(num1, num2)
	return inner
	
# 使⽤装饰器装饰函数
@logging
def sum_num(a, b):
	result = a + b
	print(result)

sum_num(1, 2)

运行结果:

--正在努⼒计算--
3

  1. 装饰带有返回值的函数
# 添加输出⽇志的功能
def logging(fn):
	def inner(num1, num2):
		print("--正在努⼒计算--")
		result = fn(num1, num2)
		return result
	return inner
	
# 使⽤装饰器装饰函数
@logging
def sum_num(a, b):
	result = a + b
	return result

result = sum_num(1, 2)
print(result)

运行结果

--正在努⼒计算--
3

  1. 装饰带有不定长参数的函数
# 添加输出⽇志的功能
def logging(fn):
	def inner(*args, **kwargs):
		print("--正在努⼒计算--")
		fn(*args, **kwargs)
	return inner
	
# 使⽤语法糖装饰函数
@logging
def sum_num(*args, **kwargs):
	result = 0
	for value in args:
		result += value
for value in kwargs.values():
	result += value
		print(result)
		
sum_num(1, 2, a=10)

运行结果:

--正在努⼒计算--
13
  1. 通用装饰器
# 添加输出⽇志的功能
def logging(fn):
	def inner(*args, **kwargs):
		print("--正在努⼒计算--")
		result = fn(*args, **kwargs)
		return result
	return inner
	
# 使⽤语法糖装饰函数
@logging
def sum_num(*args, **kwargs):
	result = 0
	for value in args:
		result += value
	for value in kwargs.values():
		result += value
	return result
	
@logging
def subtraction(a, b):
	result = a - b
	print(result)
	result = sum_num(1, 2, a=10)
	print(result)

subtraction(4, 2)

运行结果:

--正在努⼒计算--
13
--正在努⼒计算--
2

  1. 小结
    通用装饰器的语法格式:
# 通⽤装饰器
def logging(fn):
	def inner(*args, **kwargs):
		print("--正在努⼒计算--")
		result = fn(*args, **kwargs)
		return result
	return inner

多个装饰器的使用

  1. 多个装饰器的使用示例代码
def make_div(func):
	"""对被装饰的函数的返回值 div标签"""
	def inner(*args, **kwargs):
		return "<div>" + func() + "</div>"
		return inner
		
def make_p(func):
	"""对被装饰的函数的返回值 p标签"""
	def inner(*args, **kwargs):
		return "<p>" + func() + "</p>"
	return inner


# 装饰过程: 1 content = make_p(content) 2 content = make_div(content)
# content = make_div(make_p(content))
@make_div
@make_p
def content():
	return "⼈⽣苦短"
	
result = content()

print(result)

代码说明:

  • 多个装饰器的装饰过程是: 离函数最近的装饰器先装饰,然后外面的装饰器再进行装饰,由内到外的装饰过程
  1. 小结
    多个装饰器可以对函数进行多个功能的装饰,装饰顺序是由内到外的进行装饰

带有参数的装饰器
带有参数的装饰器就是使用装饰器装饰函数的时候可以传入指定参数,语法格式: @装饰器(参数,…)
错误写法:

def decorator(fn, flag):
	def inner(num1, num2):
		if flag == "+":
			print("--正在努⼒加法计算--")
		elif flag == "-":
			print("--正在努⼒减法计算--")
	result = fn(num1, num2)
	return result
return inner

@decorator('+')
def add(a, b):
	result = a + b
	return result
	
result = add(1, 3)
print(result)

执行结果:

Traceback (most recent call last):
	File "/home/python/Desktop/test/hho.py", line 12, in <module>
@decorator('+')
	TypeError: decorator() missing 1 required positional argument: 'flag'

代码说明:

  • 装饰器只能接收一个参数,并且还是函数类型。

  • 正确写法:

在装饰器外面再包裹上一个函数,让最外面的函数接收参数,返回的是装饰器,因为@符号后面必须
是装饰器实例。

# 添加输出⽇志的功能
def logging(flag):
	def decorator(fn):
		def inner(num1, num2):
			if flag == "+":
				print("--正在努⼒加法计算--")
			elif flag == "-":
				print("--正在努⼒减法计算--")
			result = fn(num1, num2)
			return result
		return inner
		
	# 返回装饰器
	return decorator
	
# 使⽤装饰器装饰函数
@logging("+")
def add(a, b):
	result = a + b
	return result
	
@logging("-")
def sub(a, b):
	result = a - b
	return result

result = add(1, 2)
print(result)

result = sub(1, 2)
print(result)

  1. 小结
    使用带有参数的装饰器,其实是在装饰器外面又包裹了一个函数,使用该函数接收参数,返回是装饰器,因为 @ 符号需要配合装饰器实例使用

类装饰器的使用

  1. 类装饰器的介绍
    装饰器还有一种特殊的用法就是类装饰器,就是通过定义一个类来装饰函数。
    类装饰器示例代码:
class Check(object):
	def __init__(self, fn):
		# 初始化操作在此完成
		self.__fn = fn
		# 实现__call__⽅法,表⽰对象是⼀个可调⽤对象,可以像调⽤函数⼀样进⾏调⽤。
	def __call__(self, *args, **kwargs):
		# 添加装饰功能
		print("请先登陆...")
		self.__fn()

@Check
def comment():
	print("发表评论")
	
comment()

说明:

  • @Check 等价于 comment = Check(comment), 所以需要提供一个init方法,并多增加一个fn参数。
  • 要想类的实例对象能够像函数一样调用,需要在类里面使用call方法,把类的实例变成可调用对象(callable),也就是说可以像调用函数一样进行调用。
  • 在call方法里进行对fn函数的装饰,可以添加额外的功能。

执行结果:

请先登陆...
发表评论

  • 小结
  • 想要让类的实例对象能够像函数一样进行调用,需要在类里面使用call方法,把类的实例变成可调 用对象(callable)
  • 类装饰器装饰函数功能在call方法里面进行添加
发布了58 篇原创文章 · 获赞 14 · 访问量 9373

猜你喜欢

转载自blog.csdn.net/lh_hebine/article/details/99187466