Python装饰器可以实现什么,还有什么有趣的用法
Admin 2022-07-25 群英技术资讯 286 次浏览
它的使用场景同样很多,比较简单的场景包含打印日志、统计运行时间,这类例子和用法网上已经很多了:
def time_dec(func): def wrapper(*arg): t = time.clock() res = func(*arg) print func.func_name, time.clock()-t return res return wrapper @time_dec def myFunction(n): ...
再进阶一些的,可以用来校验函数传入参数类型、线程同步、单元测试等:
@parameters( (2, 4, 6), (5, 6, 11), ) def test_add(a, b, expected): assert a + b == expected
目前可以用的装饰器可以分为如下几类:
下面就分别来介绍一下。
关于自定义的装饰器在前面已经提到了,我在开发过程中经常用到的就是日志打印、计时、数据校验等场景,通过装饰器可以提高代码的简洁性,避免重复造轮子。
除了这些基本的,也有一些比较实用的地方。
作为开发同学,肯定会遇到不同的运行环境:
有时候,我们期望一个函数在不同环境下执行不同的过程,产出不同的结果,做一些环境的隔离和差异化处理。
通过装饰器就可以很好的解决:
production_servers = [...] def production(func: Callable): def inner(*args, **kwargs): if gethostname() in production_servers: return func(*args, **kwargs) else: print('This host is not a production server, skipping function decorated with @production...') return inner def development(func: Callable): def inner(*args, **kwargs): if gethostname() not in production_servers: return func(*args, **kwargs) else: print('This host is a production server, skipping function decorated with @development...') return inner def sit(func: Callable): def inner(*args, **kwargs): print('Skipping function decorated with @sit...') return inner @production def foo(): print('Running in production, touching databases!') foo() @development def foo(): print('Running in production, touching databases!') foo() @inactive def foo(): print('Running in production, touching databases!') foo()
简单的介绍一下这段代码。
在这里,先是罗列了生产环境的服务列表,然后分别定义了生产、开发、测试环境的装饰器,然后给同名的函数就可以配上对应的装饰器。
在执行代码的过程中,这段代码会首先获取hostname,自动判断所在环境,然后执行对应函数。
上面是根据我们在开发过程中遇到的个性化场景进行来自定义一个装饰器。
作为一款以工具包著称的编程语言,Python中也有很多工具包提供了一些实用的装饰器。
以日志为例,这是每个程序员都无法绕开的。
调试程序对于大多数开发者来说是一项必不可少的工作,当我们想要知道代码是否按照预期的效果在执行时,我们会想到去输出一下局部变量与预期的进行比对。目前大多数采用的方法主要有以下几种:
但是这些方法有着无法忽视的弱点:
其中有一款不错的开源工具PySnooper就通过装饰器把这个问题巧妙的解决了。
PySnooper的调用方式就是通过@pysnooper.snoop的方式进行使用,该装饰器可以传入一些参数来实现一些目的,具体如下:
参数描述:
举个例子:
import numpy as np import pysnooper @pysnooper.snoop() def one(number): mat = [] while number: mat.append(np.random.normal(0, 1)) number -= 1 return mat one(3)
然后,就会给出如下输出:
Starting var:.. number = 3
22:17:10.634566 call 6 def one(number):
22:17:10.634566 line 7 mat = []
New var:....... mat = []
22:17:10.634566 line 8 while number:
22:17:10.634566 line 9 mat.append(np.random.normal(0, 1))
Modified var:.. mat = [-0.4142847169210746]
22:17:10.634566 line 10 number -= 1
Modified var:.. number = 2
22:17:10.634566 line 8 while number:
22:17:10.634566 line 9 mat.append(np.random.normal(0, 1))
Modified var:.. mat = [-0.4142847169210746, -0.479901983375219]
22:17:10.634566 line 10 number -= 1
Modified var:.. number = 1
22:17:10.634566 line 8 while number:
22:17:10.634566 line 9 mat.append(np.random.normal(0, 1))
Modified var:.. mat = [-0.4142847169210746, -0.479901983375219, 1.0491540468063252]
22:17:10.634566 line 10 number -= 1
Modified var:.. number = 0
22:17:10.634566 line 8 while number:
22:17:10.634566 line 11 return mat
22:17:10.634566 return 11 return mat
Return value:.. [-0.4142847169210746, -0.479901983375219, 1.0491540468063252]
局部变量值、代码片段、局部变量所在行号、返回结果等,这些关键信息都输出了,既方便,又清晰。
除了自定义和第三方工具包之外,Python还内置了很多不错的装饰器,例如@abc.abstractmethod、@asyncio.coroutine、@classmethod等等。
这里着重提一个非常强大的装饰器,能够极大的提升Python的运行速度和效率,通过一个装饰器能够将Python代码的执行速度提升上万倍,这个装饰器就是@functools.lru_cache。
以比较知名的斐波那契数列的例子来演示一下。
由于它递归计算的过程中,还会用到之前计算的结果,因此会涉及较多的重复计算,下面先看一下正常计算的耗时情况。
import time as tt def fib(n): if n <= 1: return n return fib(n-1) + fib(n-2) t1 = tt.time() fib(30) print("Time taken: {}".format(tt.time() - t1)) # 0.2073
n等于30时,耗时0.2073。
加上@functools.lru_cache装饰器再看一下:
import time as tt import functools @functools.lru_cache(maxsize=5) def fib(n): if n <= 1: return n return fib(n-1) + fib(n-2) t1 = tt.time() fib(30) print("Time taken: {}".format(tt.time() - t1)) # 1.811981e-05
耗时为1.811981e-05,足足差了4个量级,快了10000+倍!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
猜你喜欢
1.reshape2.flatten3.ravel4.stack(1)concatenate(2)vstack(3)dstack(4)hstack(5)r,c模式5.split(1)split(2)vsplit和hsplit6.repeat(1)标量参数(2)列表参数7.tile(1)标量参数(2)元组参数8.sor
这篇文章主要介绍了python 如何破解加密zip文件的密码,帮助大家更好的理解和学习使用python,感兴趣的朋友可以了解下
这篇文章主要为大家介绍了Python Map 函数,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
在列表,元组,实例,类,字典和函数中存在循环引用问题。有 __del__ 方法的实例会以健全的方式被处理。给新类型添加GC支持是很容易的。
这篇文章主要介绍了学好python基本数据类型,学习python基本数据类型我们需要了解基本数据类型有数字int、布尔值bool、字符串str、列表list、元组tuple、字典dict等,其中包括他们的基本用法和其常用的方法,下面来看看文章的具体介绍吧
成为群英会员,开启智能安全云计算之旅
立即注册Copyright © QY Network Company Ltd. All Rights Reserved. 2003-2020 群英 版权所有
增值电信经营许可证 : B1.B2-20140078 粤ICP备09006778号 域名注册商资质 粤 D3.1-20240008