Python装饰器原理深度解析:从函数对象到语法糖

云舒
云舒
发布时间:2026-10-14 | 4人浏览过
原创

本文深入解析Python装饰器原理,通过风扇类比解释函数作为对象传递的概念。详细拆解装饰器实现过程,从手动调用wrapper到使用@语法糖,阐明如何在不修改原代码前提下添加前置或后置操作。涵盖带参方法处理,帮助开发者彻底理解装饰器执行逻辑。

Python装饰器的作用

作用

装饰器的核心功能在于对函数或方法进行增强。它允许开发者在不修改原有函数或方法代码的前提下,为其添加前置处理或后置处理逻辑。

例如,当需要统计各个函数的执行时间时,若直接在每个函数内部添加time.time()调用,会导致代码冗余且难以维护。

用法

网络上关于装饰器写法的教程众多,但建议先深入理解其底层原理,再掌握具体写法,这样能更灵活地应对各种场景。

装饰器实现原理

实现

理解装饰器的实现机制远比单纯记忆写法重要。简而言之,装饰器是一个接收函数对象作为参数的过程,它先执行前置操作,接着调用原函数,最后执行后置操作。

这种抽象描述可能难以直观理解,我们可以借助一个贴近生活的例子来类比。

假设你拥有这样一台小风扇:

这台风扇支持充电,配备开关。打开开关后扇叶旋转开始工作;你可以插电使用,也可以充满电后携带至他处使用。

在“一切皆对象”的Python中,这台风扇即可视为一个对象,其核心功能是产生风力。


def fengshan():
  return '出风'

为了便于与示例结合,我们采用拼音命名方式。

此时,我们定义了一个名为fengshan的函数,其返回值是字符串“出风”。

具备一定Python基础的用户应当清楚如何调用此方法。


def fengshan():
  return '出风'
print(fengshan())

请勿觉得此基础概念繁琐,理解装饰器必须掌握这一基石:调用函数的方式是函数名后加括号fengshan()。这里的括号()等同于执行函数的开关,若不加括号:


def fengshan():
  return '出风'
print(fengshan)

返回的将是函数对象本身(即示例中的风扇实体)。

<function fengshan at 0x7f8e7c4a6950>

这表示名为fengshan的函数对象,其内存地址为0x7f8e7c4a6950。

此时,我们可以将该函数对象“带走”,并在其他位置使用。


def fengshan():
  return '出风'
 
func = fengshan
print(fengshan)
print(func)

返回

<function fengshan at 0x7f570eaf3950> <function fengshan at 0x7f570eaf3950>

这表明变量func与fengshan指向同一内存地址,二者等价。因此,执行func()等同于执行fengshan()。


def fengshan():
  return '出风'
 
func = fengshan
print('下面是执行fengshan')
print(fengshan())
print('下面是执行func')
print(func())

返回

以下是执行fengshan()的结果:

出风

以下是执行func()的结果:

出风

理解至此,即可明白装饰器的实现逻辑。让我们通过另一个示例进一步说明。


def fengshan():
  return '出风'
def wrapper(func):
  return func
print(fengshan)
print(wrapper(fengshan))

此例中,除了保留原有的fengshan函数外,还定义了一个wrapper函数。

由于Python中一切皆对象,函数也是对象,且函数的参数可以接收对象,因此函数对象可作为参数传递给另一个函数wrapper。

该wrapper函数未做额外处理,仅返回接收到的func对象。打印两个对象可知,它们实际上是同一对象。

<function fengshan at 0x7f9b0c92f950> <function fengshan at 0x7f9b0c92f950>

至此,你已理解装饰器的基本实现。若跟随代码敲写一遍,便已编写了一个简易装饰器。只需稍加修改,例如在wrapper内部执行接收的func,并在其前后添加操作:


def wrapper(func):
  print('在wrapper中执行func前')
  print(func())
  print('在wrapper中执行func后')
wrapper(fengshan)

返回

在wrapper中执行func前

出风

在wrapper中执行func后

若觉得神奇难懂,可回顾风扇图片重读。理解上述代码后,我们将加速完成真正的装饰器编写。

装饰器的实际用法与语法糖

用法

当理解函数定义与调用过程后,我们考虑实际场景。上一段代码中,我们改变了原有函数的调用方式。

调用方式从fengshan()变为func(fengshan)。

为实现不改变原有代码和调用方式即可添加前置或后置操作,需进一步优化装饰器。


def fengshan():
  print('出风')
 
 
def wrapper(func):
  def f():
    print('在wrapper中执行func前')
    func()
    print('在wrapper中执行func后')
  return f
 
fengshan = wrapper(fengshan)
fengshan()

为清晰展示执行过程,将fengshan内部的return改为print。

返回

在wrapper中执行func前

出风

在wrapper中执行func后

此处的改动是在wrapper原有实现中再包裹一层方法f。回顾风扇例子,执行wrapper()时发生了什么?

wrapper(func)返回的是一个函数对象f,该对象的开关未打开,f内部代码不会立即执行。

我们再用同名变量fengshan接收此函数对象f,并在最后一行打开fengshan的开关——fengshan()。此时,函数对象f中的代码才被执行。

若仍不理解,建议从风扇图片开始重读。若已理解,建议再复习一遍。至此,我们已完成一个装饰器的编写。为便于使用,Python提供了更简便的方法。


def wrapper(func):
  def f():
    print('在wrapper中执行func前')
    func()
    print('在wrapper中执行func后')
  return f
@wrapper
def fengshan():
  print('出风')
fengshan()

返回

在wrapper中执行func前

出风

在wrapper中执行func后

支持带参方法的装饰器

补充知识

若已理解装饰器的执行逻辑,便知如何让装饰器支持带参数的方法,这也是编写装饰器的常规操作。


def wrapper(func):
  def f(*args, **kwargs):
    print('在wrapper中执行func前')
    func(*args, **kwargs)
    print('在wrapper中执行func后')
  return f
@wrapper
def fengshan(str_obj):
  print(str_obj)
fengshan(str_obj='出风')

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表