Python闭包与装饰器原理及实例解析

季宁
季宁
发布时间:2026-10-11 | 3人浏览过
原创

本文深入解析Python中闭包与装饰器的核心原理。通过代码示例,展示如何构建闭包,并逐步演示从基础装饰器到支持参数传递的复杂装饰器的实现过程。重点讲解函数作为参数传递、返回值处理及参数解包的技巧,帮助开发者掌握装饰器的灵活应用。

闭包与装饰器的基础概念

在Python中,闭包是指一个函数内部定义了另一个函数,并返回该内部函数的引用。这种机制使得内部函数可以访问外部函数的变量,即使外部函数已经执行完毕。装饰器则是基于闭包原理的一种设计模式,它允许我们在不修改原函数代码的前提下,动态地增加或修改函数的功能。

闭包的实现

闭包的核心在于“返回函数”。以下代码展示了如何定义一个包含内部函数的外层函数,并通过返回内部函数来实现闭包:

def func(name): # 定义外层函数
  def inner_func(age): # 内层函数
    print('name: ', name, ', age: ', age)
  return inner_func # 注意此处要返回,才能体现闭包

bb = func('jayson') # 将字符串传给func函数,返回inner_func并赋值给变量
bb(28) # 通过变量调用func函数,传入参数,从而完成闭包
>>
name: jayson , age: 28

在上述代码中,func函数返回了inner_func的引用。当我们将func('jayson')的结果赋值给变量bb时,bb实际上指向了inner_func。通过调用bb(28),我们完成了闭包的调用过程。

装饰器的基本形式

装饰器本质上是一个函数,它接收一个函数作为参数,并返回一个新的函数。以下代码展示了最简单的装饰器实现:

def deco(func): # 传入func函数。
  print('decoration')
  return func
def test():
  print('test_func')

test = deco(test) # 对函数进行装饰。执行了deco函数,并将返回值赋值给test
>>
# 输出deco的运行结果
decoration

test() # 运行装饰后的函数
>>
test_func

这里,deco函数接收test函数作为参数,打印“decoration”,然后返回test。通过test = deco(test),我们将test函数替换为装饰后的版本。调用test()时,实际上执行的是装饰后的逻辑。

使用@语法糖简化装饰器

Python提供了@语法糖,使得装饰器的使用更加简洁。以下代码展示了如何使用@语法糖:

def deco(func): # 传入func函数。
  print('decoration')
  return func

@deco # 等价于上一代码中test = deco(test),不过上一代码需放在定义test之后
def test():
  print('test_func')

>>
# 输出deco的运行结果
decoration

test() # 运行装饰后的函数
>>
test_func

注意,@deco在函数定义时就会执行,因此“decoration”会在定义test函数时立即打印。

处理原函数的返回值

在实际应用中,原函数可能有返回值。为了保持装饰器的通用性,包裹函数需要返回原函数的返回值。以下代码展示了如何处理返回值:

def deco(func): 
  print('decoration') # 此处未调用func函数时,会直接执行
  def wrapper(): # 名称自定义,一般用wrapper
    print('execute') # 此处未调用func函数时,不会执行
    func() # 执行函数
  return wrapper # 此处返回wrapper给func,通过外部func()执行

@deco # 注意:此处不能有括号。有括号的形式是func未传入最外层deco(),传入deco的子函数中
def test():
  print('test_func') 
# 定义完函数后,会直接执行装饰器deco(test)
>>
decoration

# 调用test,执行test函数
test()
>> 
test_func

在上述代码中,wrapper函数调用了func(),但没有返回其结果。为了保持装饰器的通用性,我们需要修改wrapper函数,使其返回func()的结果:

def deco(func): 
  print('decoration')
  def wrapper():
    print('execute')
    a = func() # 执行函数,并返回值
    print('done')
    return a # 将func的返回值一并返回
  return wrapper

@deco
def test():
  print('test_func')
  return 5 # 增加返回值
>>
decoration

#调用test
test()
>>
execute
test_func
done
 # 此处是test函数的返回值

处理原函数的参数

为了处理原函数的参数,包裹函数需要使用*args和**kwargs来接收任意数量的位置参数和关键字参数。以下代码展示了如何处理参数:

import time

def deco(func):
  def inner(*arg, **kwarg): # 此处传入参数
    begin_time = time.time()
    time.sleep(2)
    a = func(*arg, **kwarg) # 调用函数,使用传入的参数
    end_time = time.time()
    print('运行时间:', end_time - begin_time)
    return a
  return inner

@deco
def test(a):
  print('test function:', a)
  return a

# 调用函数
test(5)
>>
test function: 5
运行时间: 2.0003252029418945
 # 5是函数返回的值

通过*arg和**kwarg,我们可以灵活地处理各种参数组合,而无需修改装饰器本身。

带参数的装饰器

有时,我们需要为装饰器本身传递参数。这可以通过在装饰器外层再嵌套一个函数来实现。以下代码展示了如何实现带参数的装饰器:

import time

def outer(): # 在原装饰器外套一层函数,将装饰器封装在函数里面。(outer自定义)
  def deco(func): # 原装饰器,后面的代码一样
    def inner(*arg, **kwarg): 
      begin_time = time.time()
      time.sleep(2)
      a = func(*arg, **kwarg) 
      end_time = time.time()
      print('运行时间:', end_time - begin_time)
      return a
    return inner
  return deco # 注意:此处需返回装饰函数

@outer() # 此处就需要加括号,其实是调用了outer()函数,将test传进其子函数
def test(a):
  print('test function:', a)
  return a

test(4)
>>
test function: 4
运行时间: 2.000566005706787
 # 返回4

在上述代码中,outer函数返回了deco函数。通过@outer(),我们调用了outer函数,并将test函数传递给了deco。

根据参数选择不同装饰逻辑

我们可以根据传入的参数,选择不同的装饰逻辑。以下代码展示了如何实现:

import time

def outer(choose): # 在最外层函数中加入参数
  if choose==1: # 通过choose参数,选择装饰器
    def deco(func):
      def inner(*arg, **kwarg):
        print('decoration1')
        begin_time = time.time()
        time.sleep(2) # 睡眠2s
        a = func(*arg, **kwarg) 
        end_time = time.time()
        print('运行时间1:', end_time - begin_time)
        return a
      return inner
    return deco
  
  else:
    def deco(func):
      def inner(*arg, **kwarg): 
        print('decoration2')
        begin_time = time.time()
        time.sleep(5) # 睡眠5s
        a = func(*arg, **kwarg) 
        end_time = time.time()
        print('运行时间2:', end_time - begin_time)
        return a
      return inner
    return deco

@outer(1) # 由于outer中有参数,此处必须传入参数
def test1(a):
  print('test function1:', a)
  return a

@outer(5) # 传入另一个参数
def test2(a):
  print('test function2:', a)
  return a


# 分别调用2个函数(2个函数装饰器相同,装饰器参数不同)
test1(2) # 调用test1
>>
decoration1
test function1: 2
运行时间1: 2.000072717666626 # 2秒
 # test1的返回值

test2(4) # 调用test2
>>
decoration2
test function2: 4
运行时间2: 5.000797986984253 # 5秒
 # test2的返回值

通过choose参数,我们可以选择不同的装饰逻辑。调用test1(2)和test2(4)时,分别执行了不同的装饰逻辑。

总结

本文详细解析了Python中闭包与装饰器的原理及实现。通过逐步演示从基础装饰器到带参装饰器的过程,展示了如何处理函数参数、返回值以及动态选择装饰逻辑。掌握这些技巧,可以帮助开发者更灵活地应用装饰器,提升代码的可维护性和扩展性。

以上就是Python闭包与装饰器原理及实例解析的详细内容,更多关于Python闭包与装饰器的资料请关注本站其它相关文章!

相关标签:

本站声明

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

Python 相关产品和应用

全部下载

专题列表