Python闭包与装饰器原理及实例解析
本文深入解析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闭包与装饰器的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









