深入理解Python装饰器:从原理到实战应用

小岛来信
小岛来信
发布时间:2026-10-14| 6人浏览过
原创

本文深入解析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 装饰器的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。