理解python函数装饰器@decorator


函数装饰器是python有别于其他语言的主要特征之一,这也是充分发挥了动态语言的优势,可以使我们在编写程序时更加简洁。但最开始接触函数装饰器有点难以理解,本文尽量用简单的语言来理解函数装饰器。

一、储备知识点

在理解函数装饰器之前,最好储备并理解了以下Python的基础知识:

  • 自定义函数。包括函数参数、实参、形参、位置参数、关键字参数、不定长的列表类参数和字典类参数,以及函数返回值。
  • 局部函数和函数嵌套。
  • 函数作为另外一个函数的参数。最好理解一下参数传递方式。
  • 变量的作用域。全局变量和局部变量,及其查看方法:globals(),loacals()

二、理解装饰行为

生活中,化妆可能是最容易理解装饰行为的例子之一。
女人化妆,就是用化妆品来装饰女人,然后这个女人还是这个女人,并没有根本上的改变,只是被装饰了,更好看或者更丑了而已。可以理解为女人被化妆品包裹了,或者装饰了。
上面的例子中,女人和化妆品都看做是物,而不是行为,不符合要完成函数功能的意义。女人和化妆品更像是类的实例,下面的生活中的例子更接近函数:

def 散步():
	pass

def 听歌():
	pass

上面定义了两个行为(函数),散步和听歌。按照女人和化妆品的例子,我想让散步的行为不那么枯燥,用听歌()行为来装饰散步()行为。于是,就可以在散步中听歌,然而散步依然是散步,并没有根本上改变,只是在散步的时候增加了听歌。散步行为用听歌行为来进行装饰了,或者被听歌函数包裹了。
用伪代码来表示这个装饰行为:
散步=听歌装饰的(散步)
在赋值符号“=”号右边是被听歌行为装饰了的散步行为,或者说被听歌函数包裹了。同时,将装饰的结果赋值给散步,使得散步依然是散步,只是在散步的同时增加了听歌行为。
下面,我们来实现 散步=听歌装饰的(散步) 这个伪代码:

# 定义散步函数
def 散步():
	print("这是散步行为")

# 定义听歌函数,并接受函数作为形参
def 听歌(function):
	print("这是听歌行为")
	return function

# 开始用听歌装饰散步,并赋值给散步
散步=听歌(散步)
# 执行散步
散步()

#output:
#这是听歌行为
#这是散步行为

注意:上面的代码可以复制后直接运行。python3支持中文变量名。
散步行为通过听歌行为装饰过后,就增加了听歌的功能。
上述代码也可以用python的装饰器的形式表示,加上“@”。如下:

# 定义听歌函数,并接受函数作为形参
def 听歌(function):
	print("这是听歌行为")
	return function

# 开始装饰
# 定义散步函数
@听歌
def 散步():
	print("这是散步行为")
# 执行散步函数    
散步()
#output:
#这是听歌行为
#这是散步行为

可以看出,通过@符号进行装饰后的,效果和“散步=听歌(散步)”是一样的,这就是python装饰器的本质,只不过python用“@”符号进行了简化。
但是,请注意!!! 上面的例子并不是完整的装饰器,装饰的过程是有问题的,只是为了简化理解而举例的。那么,问题在哪里呢?请接着看第三节。

三、python的函数装饰器

可能你已经发现了,在装饰的过程中(也就是 “散步=听歌(散步) ”过程中,或者“@听歌”过程中,两者是一样的),听歌函数会执行

print("这是听歌行为")

这行代码。
也就是说,output中的“这是听歌行为”是在装饰过程中执行输出的,并不是装饰完成过后,由新的 散步()函数来执行输出的。这样显然是与我们现实中的装饰的含义不一致的,这是有问题的。下面,就此问题进行改进:

# 定义听歌函数,并接受函数作为形参
def 听歌装饰器(function):
    def 听歌():
        print("这是听歌行为")
        function()
    return 听歌

# 开始装饰
# 定义散步函数
@听歌装饰器
def 散步():
	print("这是散步行为")

# 执行散步函数
散步()

#output:
#这是听歌行为
#这是散步行为

上面代码中,我们将听歌行为封装在听歌装饰器里面,然后用听歌装饰器去装饰散步行为。上述代码的本质依然是:散步=听歌装饰器(散步),只不过用“@”符号进行简化。
听歌装饰器(function)里面,将听歌行为封装并返回赋值给散步行为,完成了完整的装饰过程。理解了上面的内容,就理解了python装饰器的装饰过程。
我们在编写代码的过程中,在执行某个函数时,会遇到在执行函数之前或之后同时执行其他一些功能函数,这也可以用装饰器来进行简化,达到代码复用的目的,让代码更加简洁。看下面的例子:

def training_decorator(f):
	def change_sportswear():
		print("Change sportswear")
	
	def bathe():
		print("bathe")
		
	def decorator():
		change_sportswear()
		f()
		bathe()

	return decorator

@training_decorator
def training():
	print("training")

training()

#output:
'''
Change sportswear
training
bathe
'''

上述代码中,函数training()通过装饰器training_decorator后,在执行前和执行后都完成了一些函数的功能,比如change_sportswear()和bathe()。

四、装饰器的典型应用场景

在上面的例子中,training()执行前后都要完成某些特定功能,如果在多个类似training()的函数执行前都要完成相同的功能,用装饰器显然就要方便和简洁的多。最典型的应用场景就是webapp的用户验证功能:

def user_authentication(function):
	pass
	
@user_authentication
def edit_function():
	pass

@user_authentication
def add_function():
	pass
	
@user_authentication
def del_function():


Flask和Django web框架大量应用了函数装饰器。上面的装饰器都是用函数来进行装饰的,python的装饰器用法也支持用类进行装饰,那个不在本文介绍之列,本文的重点是帮助如何理解python的函数装饰器。装饰器还有很多用法细节和应用场景,比如带参数的装饰器等等,其本质仍然是:装饰后赋值给被装饰的函数,此文中就不再介绍了,感兴趣的自行深入学习。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值