python中装饰器的使用方式,非常简单易上手哦

本文深入介绍了Python中的装饰器,从在函数中定义函数开始,逐步讲解简单装饰器、使用@的装饰器、处理函数名错误以及创建可接受参数的装饰器。装饰器是基于闭包的一种语法特性,可以简化代码并提供额外的功能,如计算开始和结束的提示。通过functools.wraps可以解决装饰器中函数名显示错误的问题。最后展示了如何创建接受参数的装饰器,增加了装饰器的灵活性。

在这里插入图片描述
上一篇文章写了python中闭包的基础使用方式,而闭包在python中较为常见的用法就是在装饰器中出现,由于前段时间看了一些装饰器的文章,因此本文想要简要介绍一下python中装饰器。需要注意的是最好先了解闭包的使用方式再来看装饰器的使用方式哟,因为装饰器实际上就是在闭包的基础上运作的。

装饰器实际上是针对python函数中的一种语法糖,使用装饰器能够在某些情况下大大减少代码量,那接下来就看一下python装饰器到底是怎样一种形式吧!


在函数中定义函数

在python中函数里是可以再定义函数的,先上例子:

def greeting(country='China'):

	def print_hello():
		print('hello')

	def print_nihao():
		print('你好')

	if country == 'China':
		return print_nihao
	else:
		return print_hello

a = greeting()
a()
b = greeting('America')
b()
# 运行结果是  你好,hello

在这个例子中,能够看到将内部定义的函数print_hello在输入的国家非中国时会被return,而print_nihao则是在输入国家为中国时被return。这里的return实际上上篇文章已经讲过了,其实就是因为在python中万物皆对象,因此return print_nihao就代表返回了一个函数名,但要使函数执行,则还至少需要加个括号。这里令a = greeting()实际上是代表将greeting函数的执行结果赋值给了a(即a代表着greeting的运行结果),greeting的执行结果获取默认参数即country=‘China’,return的是print_nihao,实际上也就是说a = print_nihao,这里只是一个函数名的传递,若需要开始执行print_nihao,那么加个括号就行啦(即a(),因为这里不需要额外的参数)。执行print_nihao,就打印出了你好

这里看起来是不是和闭包的使用方式很相近,这也是要制作装饰器的基础,因为装饰器就是要在函数中定义函数及运行函数。接下来看一下简单的装饰器。

简单装饰器

def print_name():
	print('牛魔王')

def greeting(func):   # 传递入函数名
	func()
	print('你好')

greeting(print_name)

这个例子中将函数名作为参数进行传递,在greeting函数中再运行传递入的函数,实际上这就是装饰器最基础的形式啦,就是将要运行的函数传递到另外的函数中,在另个函数运行过程中调用此函数的功能,这样就不用再重复书写此函数的代码了。同时,在传入不同函数名时还能发挥不同的功能。

看一个更加完整的装饰器:

def add(a,b):   # 加法
	return a+b

def sub(a,b):   # 减法
	return a - b
	
def multiply(a,b): # 乘法
	return a**b

def divide(a,b):  # 除法
	return a/b

def decorater(func):
	def wrapper(*args,**kargs):   # 可以传入的任意参数
		print("计算开始") 
		print("计算结果为:",func(*args,**kargs))   # 调用传入的函数,并打印结果
		print("计算结束")
	return wrapper    # 返回内函数

ad = decorater(add)   # ad此时代表的是wrapper函数,后续调用时通过wrapper传入参数给add函数
ad(4,5) 
mu = decorater(multiply)
mu(4,5)
su = decorater(sub)
su(4,5)
di = decorater(divide)
di(4,5)

这个结果我就不展示啦,其实就是计算开始加计算结果再加上计算结束。

从这个例子就能看出,一个装饰器能完成很多之前可能需要很多次手动重复的工作,此处装饰器可以用在很多的计算过程中,能够起到打印计算开始和计算结束的效果,因此装饰器在某些工作中还是很有用处的。

使用@的装饰器

其实python并不需要一直像上面一样每次都赋值一次(即ad = decorater()的过程),而是有语法糖形式即@符号,@符号能直接开启函数装饰器的功能,加到某个函数之前就装饰了某个函数。

上面的代码改造后的样子:

def decorater(func):
	def wrapper(*args,**kargs):   # 可以传入的任意参数
		print("计算开始") 
		print("计算结果为:",func(*args,**kargs))   # 调用传入的函数,并打印结果
		print("计算结束")
	return wrapper    # 返回内函数

@decorater
def add(a,b):   # 加法
	return a+b

@decorater
def sub(a,b):   # 减法
	return a - b

@decorater	
def multiply(a,b): # 乘法
	return a**b

@decorater
def divide(a,b):  # 除法
	return a/b

add(4,5)
sub(4,5)
multiply(4,5)
divide(4,5)

执行后会发现结果与上面的运行结果一样,这样是不是就十分方便啦!

打印要执行的函数名时出错(functools.wraps的使用)

执行下面的代码,结果得到的add的函数名为wrapper。这是因为python内部是将add函数的内容都传递给了内函数即wrapper,此时执行相当于在执行与add功能相同的wrapper函数。

def decorater(func):
	def wrapper(*args,**kargs):   # 可以传入的任意参数
		print("计算开始")
		# print(func.__name__)
		print("计算结果为:",func(*args,**kargs))   # 调用传入的函数,并打印结果
		print("计算结束")
	return wrapper    # 返回内函数

@decorater
def add(a,b):   # 加法
	return a+b

print(add.__name__)

显然这不是我们想要的。但functools中有个wraps模块能帮我们解决这个问题。

from functools import wraps
def decorater(func):
	@wraps(func)
	def wrapper(*args,**kargs):   # 可以传入的任意参数
		print("计算开始")
		# print(func.__name__)
		print("计算结果为:",func(*args,**kargs))   # 调用传入的函数,并打印结果
		print("计算结束")
	return wrapper    # 返回内函数

@decorater
def add(a,b):   # 加法
	return a+b

print(add.__name__)

这样执行结果就变为了add。

可以传入参数的装饰器

若是装饰器本身需要传入参数,那么就会稍微复杂一点,需要三层嵌套,但是使用起来也是一样。下面看例子:

def outside(text):
	def decorater(func):
		def wrapper(*args,**kargs):   # 可以传入的任意参数
			print("计算开始")
			# print(func.__name__)
			print("计算结果为:",func(*args,**kargs),text)   # 调用传入的函数,并打印结果
			print("计算结束")
		return wrapper    # 返回内函数
	return decorater

@outside('看得到计算结果不?')
def add(a,b):   # 加法
	return a+b

add(4,5)

运行结果:

在这里插入图片描述

叮!

实际上可以看出装饰器就是在闭包的基础上来的,因此我觉得最好是理解一下闭包的概念啦,我之前就有写过,哈哈。从这里穿越

参考:Python 函数装饰器

参考:装饰器

参考:https://www.zhihu.com/question/26930016/answer/1047233982

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值