深入理解Python装饰器:从原理到实战应用
本文深入解析Python装饰器的核心原理,涵盖函数对象、嵌套函数与闭包概念。通过对比手动封装与使用@语法糖两种实现方式,展示装饰器在权限校验等场景下的应用。同时探讨装饰器对代码可读性的提升及潜在的性能损耗,帮助开发者在面试与工程中合理使用。
前言
前言
作为Python高级语言特性的重要组成部分,「装饰器」提供了一种极其便捷的函数修改方式。恰当使用装饰器能够显著提升代码的可读性与可维护性,兼具便利性与灵活性。
从本质上看,装饰器就是一个函数。其核心特征在于能够接收其他函数作为参数,并返回一个新的函数来替换原函数。
初看上述描述可能略显抽象,为了深入理解装饰器的原理,我们需要先厘清三个基础概念:「什么是函数对象」、「什么是嵌套函数」以及「什么是闭包」。关于这三个问题的详细解答,我在之前的文章中已有论述,建议点击下方链接查阅,这也是面试中高频考察的知识点:
https://www.jb51.net/article/158738.htm
装饰器基础
装饰器基础
理解上述三个概念后,可以简单总结为:函数可以赋值给变量,函数支持嵌套定义,且函数对象可以作为另一个函数的参数传递。
首先通过一个示例来展示如何运用上述知识点:
def first(fun):
def second():
print('start')
fun()
print('end')
print fun.__name__
return second
def man():
print('i am a man()')
f = first(man)
f()
上述代码的执行结果如下所示:
start i am a man() end man
在上述程序中,`first`函数接收了`man`函数作为参数,并将其替换为一个新函数。这与我们在文章开头对「装饰器」的描述完全一致。基于此,我们将上述代码重构为符合Python装饰器定义与用法的标准形式,具体代码如下:
def first(func):
def second():
print('start')
func()
print('end')
print (func.__name__)
return second
@first
def man():
print('i am a man()')
man()
这段代码与之前的示例功能完全相同。主要区别在于,之前的代码直接显式调用`first`函数来封装`man`函数,而此处则使用了「语法糖」进行封装。关于语法糖的具体实现细节无需深究,只需知晓类似`@first`这种形式即为语法糖即可。
在上述代码中,`@first`位于`man`函数定义之上,表示对`man`函数应用`first`装饰器。其中,`@`是装饰器的语法符号,`first`则是装饰器的名称。
复杂场景应用
接下来,我们看一个更复杂的示例,通过该示例更深入地理解「装饰器」的实际使用及其作为Python高级特性备受推崇的原因:
def check_admin(username):
if username != 'admin':
raise Exception('This user do not have permission')
class Stack:
def __init__(self):
self.item = []
def push(self,username,item):
check_admin(username=username)
self.item.append(item)
def pop(self,username):
check_admin(username=username)
if not self.item:
raise Exception('NO elem in stack')
return self.item.pop()
上述实现了一个特殊的栈结构,其特殊性在于增加了当前用户是否为`admin`的身份校验步骤。若当前用户非`admin`,则抛出异常。代码中将身份检查逻辑封装为独立函数`check_admin`,在`push`和`pop`方法中直接调用该函数。这种方式增强了代码的可读性,减少了冗余,建议在编程时养成此类模块化意识。
下面展示上述代码使用装饰器实现的效果:
def check_admin(func):
def wrapper(*args, **kwargs):
if kwargs.get('username') != 'admin':
raise Exception('This user do not have permission')
return func(*args, **kwargs)
return wrapper
class Stack:
def __init__(self):
self.item = []
@check_admin
def push(self,username,item):
self.item.append(item)
@check_admin
def pop(self,username):
if not self.item:
raise Exception('NO elem in stack')
return self.item.pop()
对比使用「装饰器」与不使用装饰器的两种写法,乍看之下,使用装饰器的代码行数似乎更多。但仔细观察会发现,使用装饰器后代码的可读性有所提升。在未使用装饰器时,读者首先看到的是`check_admin`函数,需要理解其功能后才能继续查看栈操作逻辑;而使用装饰器后,读者首先看到的是栈的操作语句,`check_admin`的逻辑被隐藏,不会干扰对当前函数主逻辑的理解,因此可读性更佳。
正如之前文章关于「生成器」的论述,虽然Python的高级语言特性非常易用,但不可滥用。装饰器的语法相对复杂,如上文缩写的装饰器所示,其调试难度较大。此外,使用「装饰器」的程序运行速度通常比不使用装饰器的程序更慢。因此,需根据具体场景权衡使用。
以上就是无惧面试,带你搞懂python 装饰器的详细内容,更多关于python 装饰器的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









