python装饰器

python装饰器

装饰器能够不改变被装饰函数的代码逻辑和调用方式的情况下给函数扩展额外的功能。

# 如果我们需要记录函数的执行的时长
import time
def home():
	print('from home')

start_time = time.time()  # 当前时间距离1970.1.1的时间(s)
home()
end_time = time.time()  # 当前时间距离1970.1.1的时间(s)
print(end_time-start_time)  # 返回home函数执行的时长

# 能够发现上述的写法倘若在需要记录多个函数的执行时长时代码会变得重复冗余
# 通过定义记录时长的函数,并传入需要被记录的函数名使得这个功能灵活
def record_time(func):
	start_time = time.time()
	func()
	end_time = time.time()
	print(end_time-start_time)

record_time(home)  # 打印home函数执行的时长

# 但是这样便改变了被装饰函数的调用方式
# 我们定义外层函数并有一个参数接收一个函数,在内层定义函数并返回内层函数,在内层函数中执行外层函数接收的函数。
def record_time(func):
	def wrapper():
		start_time = time.time()
		func()
		end_time = time.time()
		print(end_time-start_time)
	return wrapper

home = record_time(home)  # 将被wrapper装饰的home函数返回赋值给原来的home函数名(狸猫换太子)。
home()  # 返回home函数执行的时长

# 上述对于无参函数能够使用,如果home需要接收参数就不能使用
# 我们给内层函数wrapper加上*args、*kwargs,在wrapper内func传入打散的arg、kwargs,这样home就能传值了。
def home(n):
	print('from home {}'.format(n))

def record_time(func):
	wrapper(*args,**kwargs):
		start_time = time.time()
		func(*args,**kwargs)
		end_time = time.time()
		print(end_time-start_time)
	return wrapper

home = record_time(home)
home(1)  # from home 1

# 如果被装饰函数有返回值,在装饰器内层函数中返回被装饰函数的返回值
def home(n):
	return n

def record_time(func):
	wrapper(*args,**kwargs):
		start_time = time.time()
		res = func(*args,**kwargs)
		end_time = time.time()
		print(end_time-start_time)
		return res
	return wrapper

home = record_time(home)
print(home(1))  # 1

上述代码中每定义一个需要被装饰的函数就要写 被装饰函数名 = 装饰器(被装饰函数),稍有些麻烦,python提供了装饰器语法糖可以简化书写。

def record_time(func):
	wrapper(*args,**kwargs):
		start_time = time.time()
		res = func(*args,**kwargs)
		end_time = time.time()
		print(end_time-start_time)
		return res
	return wrapper

# @装饰器外层函数名
@record_time
def home(n):
	print('from home {}'.format(n))

现在装饰器功能已经完美,但是通过help(home)查看home发现输入显示的是wrapper函数的文档描述和名字,我们需要改回到原来的home。

from functools import wraps
def record_time(func):
	@wraps(func)  # 在内层函数中装饰@wraps(func)
	wrapper(*args,**kwargs):
		start_time = time.time()
		res = func(*args,**kwargs)
		end_time = time.time()
		print(end_time-start_time)
		return res
	return wrapper

help(home)  # 此时的home函数的文档描述和名字都是原来home函数的,称为函数修正器

现在我们需要把记录时长的功能分成print输入和写入文件两种,通过判断传入参数type。但是装饰器外层和内层函数中都不能允许传入其他参数了,我们在包裹一层函数出传入type。

from functools import wraps
# 有参装饰器
def record_time_type(type):
	def record_time(func):
		@wraps(func)  # 在内层函数中装饰@wraps(func)
		wrapper(*args,**kwargs):
			if type == 'print':
				start_time = time.time()
				res = func(*args,**kwargs)
				end_time = time.time()
				print(end_time-start_time)
				return res
			elif type == 'file':
				 pass  # 记录执行时间写入文件代码
			else:
				print('未记录执行时长...')
		return wrapper
	return record_time

@record_time_type('print')
def home(n):
	print('from home {}'.format(n))
posted @ 2021-11-17 15:38  它叫鸮  阅读(30)  评论(0)    收藏  举报