Python闭包与装饰器核心机制及实战详解

桃夭
桃夭
发布时间:2026-10-14| 7人浏览过
原创

本文深入解析Python中闭包与装饰器的核心原理。通过对比匿名函数、普通函数与对象,阐明闭包“功能+数据”的传递特性。详细讲解装饰器的“开放封闭”原则,涵盖无参、有参、不定长参数及返回值处理的通用装饰器实现。重点剖析多层装饰器的执行顺序与类装饰器的用法,帮助开发者掌握Python高级函数编程技巧。

Python闭包与对象的功能对比

闭包的核心内容涉及函数与数据的结合。

匿名函数:适用于执行简单逻辑,其本质是传递函数的引用,仅包含功能逻辑。

普通函数:用于处理复杂业务逻辑,同样通过传递函数引用来实现功能调用。

闭包:能够处理相对复杂的功能场景,其传递的不仅是函数本身,还包含函数运行所需的外部数据,即实现了“功能+数据”的整体传递。

对象:适用于处理最复杂的功能场景,通过传递大量数据与多种功能方法,实现“数据+功能”的综合封装。

———————————————————

关于全局变量的修改:在普通函数内部需使用 global 关键字声明;而在闭包中,若需修改外层函数的变量,则需使用 nonlocal 关键字。

闭包的定义:指两个函数嵌套使用,内部函数可以访问并使用外部函数传递的参数或变量。最终返回的是内部函数的结构及其绑定的数据(基于个人理解)。

基于闭包机制,Python中可以引申出装饰器的概念。


def closure():
  # 在函数内部再定义一个函数,
  # 并且这个函数用到了外边函数的变量,那么将这个函数以及用到的一些变量称之为闭包
  def closure_in(x):
    print('---------我是打不死的%s--------' %x)
  return closure_in
​
x = closure()
x('小强')
​
print('*'*20)
# -----加餐---------
def closure_1(a,b,c):
  def closure_on(x):
    print('-----%s加餐-------' %b)
    print(a*x + c)
  return closure_on
​
demo = closure_1(2,'小强',3) #传closure_1函数
demo(4) #传clsure_on函数
​
#注:函数不加括号,调用的是函数本身【function】;函数加括号,调用的是函数的return结果。

装饰器基础与开放封闭原则

接下来介绍装饰器的相关内容。

代码设计应遵循“开放封闭”原则:对已存在的代码实现封闭(不随意修改源码),对功能的扩展保持开放(通过装饰器等方式添加新逻辑)。


# 装饰器的作用:为了对原来的代码上进行扩展
def decoration(func):
  def call_func():
    print('-------正在装饰 -------' )
    func()
  return call_func
​
#@decoration   #--->demo_new = decoration(demo)
def demo():
  print('demo----')
​
demo_new = decoration(demo)
demo_new()

装饰器实战:从无参到通用装饰器

使用装饰器来测试函数的运行时间:


import time
def set_func(func):
  def call_func():
    start_time = time.time()
    func()
    stop_func = time.time()
    print(‘alltimes is %f' %(stop_func-start_fun))
  return call_func
@set_func
def test1():
  print(‘——-test1———')
test1()
​
#等价于:
@set_func==test1 = set_func(test1)

1. 针对没有参数且没有返回值的函数进行装饰:


def set_func(func):
  def call_func():
    print(‘———test2——-')
    print(‘———-test3——')
    func()
  return call_func

@set_func
def test1():
  print(‘——test1——-  ')

2. 针对有参数但无返回值的函数进行装饰:


def set_func(func):
  def call_func(a): #变
    print(‘———test2——-')
    print(‘———-test3——')
    func(a) #变
  return call_func

@set_func
def test1(num):
  print(‘——test1——- %d  ' %num)
​
test1(100) —->call_func(100)
test1(200)——>call_func(200)

以下是装饰器原理的复现过程:

————————————————————————-

关键点:只要代码中出现 @函数名 这一行(即装饰器语法),在程序加载阶段就会立即执行该装饰器逻辑。

3. 针对不定长参数的函数进行装饰:


def set_func(func):
  def call_func(*args,**kwargs): #变
    print(‘———test2——-')
    print(‘———-test3——')
    func(*args,**kwargs) #(拆包)将元祖拆开,每个进行传输;
    #func(args,kwargs)—>不行,相当于传递了两个参数:一个元祖,一个字典。
  return call_func
@set_func
def test1(num,*args,**kwargs):
  print(‘——test1——- %d  ' %num)
  print(‘——test1——-  ' , args)
  print(‘——test1——- ' ,kwargs )
test1(100)
test1(100,200)
test1(100,200,300,mm=100)

注意:*args 用于保存不定长位置参数,以元组形式存储;**kwargs 用于保存不定长关键字参数,以字典形式存储(如 mm=...)。

4. 针对带有返回值的参数进行装饰,以及通用装饰器的实现:


#通用装饰器
def set_func(func):
  print(“开始进行装饰———-”)
  def call_func(*args,**kwargs): #变
    print(‘———test2——-')
    print(‘———-test3——')
    return func(*args,**kwargs) #(拆包)将元祖拆开,每个进行传输;如果没有return ret返回none。
    #func(args,kwargs)—>不行,相当于传递了两个参数:一个元祖,一个字典。
  return call_func

@set_func
def test1(num,*args,**kwargs):
  print(‘——test1——- %d  ' %num)
  print(‘——test1——-  ' , args)
  print(‘——test1——- ' ,kwargs )
  return ‘ok'  #—-返回给上面的func(),然后return func—ret
ret = test1(100)

5. 多个装饰器同时作用于同一个函数的情况:


def add_qx(func):
  print(“——开始进行装饰权限1———-”)
  def call_func(*args,**kwargs): #变
    print(‘这是权限验证1')
    return func(*args,**kwargs)
  return call_func

​
def add_xx(func):
  print(“——开始进行装饰xx功能———-”)
  def call_func(*args,**kwargs): #变
    print(‘这是xx权限验证')
    return func(*args,**kwargs)
  return call_func
@add_qx
@add_xx
def test1():
  print(‘——test1——-')
test1()

多层装饰器执行顺序与类装饰器

执行逻辑:首先执行第一个装饰器,但此时其下方的直接目标不是原始函数(根据装饰器原则,装饰器下方必须最终指向函数,否则不执行),因此第一个装饰器先挂起等待。待第二个装饰器执行完毕形成新的函数后,再将该函数交给第一个装饰器处理。因此,最终的运行结果顺序如下:

开始执行装饰xx的功能,

开始执行装饰权限1,

这是权限验证1,

这是xx权限验证,

——-test1——-,

——————装饰器练习—————- 预期输出格式:<td><h1>haha</h1></td>


def set_func_1(func):
  def call_func():
    return ‘<h1>' + func() + '</h1>'
  return call_func

​
def set_func_2(func):
  def call_func():
    return ‘<td>' + func() + '</td>'
  return call_func

@set_func_1()
@set_func_2()
def get_str():
  return ‘haha'

print(get_str())
最后执行的效果: <h1><td>haha</td></h1>

6. 使用类对函数进行装饰(了解):


class Test(object):
  def __init__(self,func):
    self.func = fun

  def __call__(self):
    print(‘这里是装饰器的功能。。。。')
    return self.func()

@Test
def get_str():
  return ‘haha'

print(get_str())

以上就是装饰器与闭包的全部内容。

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

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

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 算法库。