搞懂Python中的装饰器

简介: 搞懂Python中的装饰器

在学习Python过程中,总觉得装饰器看起来很难,这篇文章带大家搞懂Python装饰器的实现逻辑。先来看一个统计函数运行时间的装饰器

importtimedeftimer(func):
""" 计时器装饰器 """definner():
""" 内层函数 """# 统计时间start=time.time()
ret=func()
end=time.time()
# 打印运行时间print("%.2f"%end-start)
# 返回函数运行的结果returnretreturninner# 装饰器@timer# 或者是f = timer(f)deff():
time.sleep(2)
# 此时的f其实是inner函数# 运行函数f()

上面的@timer是Python的语法糖,等价写法如下

@timerdeff():
pass# 等价于f=timer(f)

可以发现,@timer其实就是将被装饰的函数当作参数传了进去,然后又重新赋给了f。之所以可以这样做,是因为Python一切皆对象,一个函数可以作为参数传到另一个函数里面,函数也可以当成变量从函数中返回出来。基于这一点,我们分析一下,上面的计时器timer是如何实现的。

timer是一个函数,它接收一个被装饰函数作为参数,因此timer必须有一个参数用来接收被装饰函数。我们目的是在运行f的时候可以自动统计f运行的时间,所以必然要有一个记录开始时间和结束时间的变量,也就是start和end。这里抛出第一个问题,start和end应该放在哪里?先来看下面一段代码

deftimer(func):
start=time.time()
ret=func()
end=time.time()
@timerdeff():
time.sleep(2)

上面这段代码将startend置于 func()之前和之后,可以达到统计运行时间的效果,但是这里会出现一个问题,f会在被@timer装饰后立刻运行,而非主动运行f()的时候去统计时间,出现这样的问题,是因为前面提到@的这种写法等价于f = timer(f),把f传进去可以发现,确实会立刻就运行了。这里抛出第二个问题,如何让传进去的f延迟运行?,即,在主动运行f()的时候,才去统计时间

解决方法是,在timer内部再加一层函数

deftimer(func):
definner():
start=time.time()
ret=func()
end=time.time()
print('%.2f'%end-start)
returnretreturninner

通过这种方法,可以达到将f装饰后,返回一个函数,即

f=timer(f)  # timer的返回值其实是inner

这样,统计部分的代码只有在f()的时候,才会去运行,从而达到了延迟运行的效果。之所以可以这样做,是因为Python中支持闭包的特性,即在外层函数运行结束后,内层函数可以继续使用外层函数中的变量,这里所使用的外层函数的变量是func

到这里,你就可以实现一个最简单的不带任何参数的装饰器。但这还远远不够,当有一天你的f函数需要增加参数以后,这个装饰器就不再适用。我们先来看一个带参数的f是如何定义并被调用的

# 定义deff(name):
print(name)
# 调用f('Jack')

当添加上装饰器以后,需要保证f可以接收参数,我们再次回到这段代码

deftimer(func):
definner():
start=time.time()
ret=func()
end=time.time()
print('%.2f'%end-start)
returnretreturninnerf=timer(f)

被装饰以后的f其实是timer内部inner函数,所以,只需要更改inner函数,只要inner函数可以接收参数,那么装饰后的f就可以接收参数。通过可变参数,可以做到不管f的参数怎么变,都可以正确接收。inner函数的具体的改造如下

deftimer(func):
definner(*args, **kwargs):
start=time.time()
ret=func(*args, **kwargs)
end=time.time()
print('%.2f'%end-start)
returnret@timerdeff(name):
print(name)
f('Jack')

除了被装饰函数有参数的情况,装饰器函数也可以接收参数,比如

@timer(10)
deff(name):
print(name)

要想完成这个需求,只需要在inner函数外面再加一层函数,像下面这样

# 装饰器先接收参数deftimer(count):
""" 计时器装饰器 """deffunc_wrapper(func):
# 通过可变参数,可以处理各种各样的函数传参definner(*args, **kwargs):
""" 内层函数 """# 统计时间start=time.time()
# 将参数值传递到被装饰的函数中ret=func(*args, **kwargs)
print(time.time() -start)
# 返回函数运行的结果returnretreturninner# 返回真正的装饰器函数returnfunc_wrapper@timer(10)
deff(name):
print(name)

这样做的的原理可以用下面的代码理解

timer=timer(10)  # 这是timer其实是func_wrapper@timerdeff(name):
print(name)

相当于在装饰器函数装饰之前,先把参数传进去,然后返回一个真正的装饰器函数,之后就和前面的过程一样了。

相关文章
|
9天前
|
开发者 Python
探索Python中的装饰器:从基础到高级应用
【9月更文挑战第23天】在编程世界中,代码的重用性和可读性一直是开发者追求的目标。Python语言通过其独特的特性——装饰器,为这一目标提供了强有力的支持。本文将从装饰器的基本概念入手,逐步深入到其在函数和类中的应用,最后探讨如何自定义装饰器以解决实际问题,旨在帮助读者掌握装饰器的使用技巧,提升代码质量。
|
7天前
|
设计模式 缓存 测试技术
探索Python中的装饰器:从基础到高级应用
在本文中,我们将深入探讨Python中的装饰器,这是一种强大且灵活的工具,用于扩展或修改函数的行为。我们将从装饰器的基本概念和定义开始,逐步讲解它们的工作原理、如何创建和使用它们。接着,我们会探讨一些常见的装饰器用例,如日志记录、缓存和权限控制等。最后,本文将讨论一些高级话题,包括带参数的装饰器、使用functools模块增强装饰器以及装饰器与类方法的兼容问题。通过综合运用这些知识,您将能够更有效地利用Python的装饰器来优化您的代码。
21 10
|
4天前
|
Python
? Python 装饰器入门:让代码更灵活和可维护
? Python 装饰器入门:让代码更灵活和可维护
11 4
|
4天前
|
缓存 测试技术 Python
探索Python中的装饰器:简化代码,提高可读性
【9月更文挑战第28天】在Python编程中,装饰器是一个强大的工具,它允许我们在不修改原有函数代码的情况下增加额外的功能。本文将深入探讨装饰器的概念、使用方法及其在实际项目中的应用,帮助读者理解并运用装饰器来优化和提升代码的效率与可读性。通过具体示例,我们将展示如何创建自定义装饰器以及如何利用它们简化日常的编程任务。
10 3
|
5天前
|
Python
Python 装饰器入门:让代码更灵活和可维护
Python 装饰器入门:让代码更灵活和可维护
10 1
|
7天前
|
Python
探索Python编程中的装饰器魔法
【9月更文挑战第26天】在Python的世界里,装饰器就像是一把瑞士军刀,小巧而功能强大。它们让代码更简洁、可维护性更强。本文将通过实际示例,带你领略装饰器的魔力,从基础到进阶,一步步揭开它的神秘面纱。
12 2
|
7天前
|
设计模式 开发者 Python
Python中的装饰器:从入门到精通
【9月更文挑战第25天】本文深入浅出地介绍了Python装饰器的使用,包括其定义、语法和实际应用。通过实例演示如何利用装饰器增强函数功能,同时探讨了装饰器的高级用法如带参数的装饰器和装饰器嵌套。最后,文章强调了在设计装饰器时应避免的常见陷阱。
|
7天前
|
程序员 开发者 Python
探索Python中的装饰器:从基础到高级应用
本文旨在全面解析Python中一个强大而灵活的特性——装饰器(Decorators)。我们将从装饰器的基本定义出发,逐步深入到它们的高级应用。通过具体的代码示例和详细的解释,读者将能够掌握如何有效地使用装饰器来增强函数和类的功能,以及如何创建自定义装饰器来解决特定问题。无论是Python初学者还是经验丰富的开发者,都能在本文中找到有价值的内容,以提升编程技巧和代码质量。
13 1
|
7天前
|
设计模式 Python
深入浅出Python装饰器
【9月更文挑战第25天】装饰器在Python中是改变函数或类行为的利器,它们通过简洁的语法糖为代码增添功能。本文将一步步揭开装饰器的神秘面纱,从基础概念出发,到实战应用,最后探讨其背后的原理。你将学会如何用装饰器简化代码、增加功能,甚至控制函数执行流程,让编程更加高效和优雅。
|
7天前
|
设计模式 缓存 中间件
探索Python中的装饰器:从入门到实践
【9月更文挑战第25天】本文通过直观的语言和生动的比喻,深入浅出地介绍Python装饰器的概念、原理及应用。我们将一起走进装饰器的魔法世界,解锁其在代码编写中的强大功能,让你的代码更加优雅和高效。
下一篇
无影云桌面