Python装饰器都有什么用呢

  小编写这篇文章的主要目的,就是给大家介绍关于python装饰器的用途方面的知识,这样对我们以后的工作也是有一定的帮助,具体用途是什么呢?下面就给各位读者详细的解答下。

  装饰器自身的价值显而易见,可以加强函数值基本功能、简单化编码、降低代码冗余。

  它的使用场景同样很多,比较简单的场景包含打印日志、统计运行时间,这类例子和用法网上已经很多了:

  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中也有很多工具包提供了一些实用的装饰器。

  以日志为例,这是每个程序员都无法绕开的。

  调试程序对于大多数开发者来说是一项必不可少的工作,当我们想要知道源代码是否按照预期的效果在执行时,我们会想到去输出一下子局部变量与预期的进行比对。目前大多数采用的方法主要有以下几种:

  Print函数

  Log日志

  IDE调试器

  但是这些方法有着无法忽视的弱点:

  繁琐

  过度依赖工具

  其中有一款不错的开源工具PySnooper就通过装饰器把这个问题巧妙的解决了。

  PySnooper的调用方式就是通过pysnooper.snoop的方式进行使用,该装饰器可以传入一些参数来实现一些目的,具体如下:

  参数描述:

  None输出日志到控制台

  filePath输出到日志文件,例如'log/file.log'

  prefix给调试的行加前缀,便于识别

  watch查看一些非局部变量表达式的值

  watch_explode展开值用以查看列表/字典的所有属性或项

  depth显示函数调用的函数的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+倍!

  到此为止,关于Python装饰器作用相关知识就为大家介绍到这里了,希望可以为各位读者带来帮助

原创文章,作者:网友投稿,如若转载,请注明出处:https://www.cloudads.cn/archives/3974.html

发表评论

登录后才能评论