python装饰器菜鸟教程,python装饰器--原来如此简单_2

  python装饰器菜鸟教程,python装饰器--原来如此简单

  装饰器本质上是一个Python函数,它允许其他函数在不修改任何代码的情况下添加额外的函数。装饰器的返回值也是一个函数对象。

  经常用在有切入需求的场景,比如日志插入、性能测试、事务处理、缓存、权限检查等。Decorator是解决这类问题的优秀设计。有了decorator,我们可以提取大量与函数本身无关的相同代码,并继续重用它们。

  让我们看一个简单的例子:

  立即定义():

  Print(2017_7_29 )现在有了一个新的需求,希望记录函数的执行日志,所以在代码中加入了日志代码:

  立即定义():

  打印( 2017_7_29 )

  Logging.warn(running )假设有类似的多个需求。怎么做?在now函数中再写一个日志?这导致大量相同的代码。为了减少代码的重复编写,我们可以通过重新定义一个函数来做到这一点:专门处理日志,然后在处理完日志之后执行真正的业务代码。

  定义使用记录(函数):

  logging.warn(%s正在运行 % func。__name__)

  函数()

  立即定义():

  打印( 2017_7_29 )

  Use_logging(现在)在逻辑上并不难,但是在这种情况下,我们每次都要把一个函数作为参数传递给log函数。而且,这种方法破坏了代码原有的逻辑结构。以前执行业务逻辑的时候,执行的是now(),现在要改成use_logging(now)。

  那么有没有更好的办法呢?当然,答案是装修工。

  首先要明白,函数也是对象,函数对象可以赋给变量,所以函数也可以通过变量调用。比如3360

  (=简单装饰器

  本质上,装饰器是返回函数的高阶函数。所以,我们想定义一个可以打印日志的装饰器,可以定义如下:

  定义日志(函数):

  定义包装(*args,**kw):

  print(call %s():%func。__name__)

  返回函数(*args,**kw)

  返回包装

  #由于log()是decorator并返回一个函数,原来的now()函数仍然存在,

  #只是现在同名的now变量指向了新函数,所以调用now()会执行新函数,即log()函数中返回的wrapper()函数。

  # wrapper()函数的参数定义是(*args,**kw),所以wrapper()函数可以接受任何参数的调用。

  #在wrapper()函数内,首先打印日志,然后立即调用原始函数。上面的日志,因为是decorator,接受一个函数作为参数,返回一个函数。现在执行3360

  现在=日志(现在)

  Now()输出结果:

  立即拨打():

  2017_7_28函数日志是装饰器。它将执行实际业务方法的func包装在函数中。看起来现在是用原木装饰的。在这个例子中,当一个函数进入时,它被称为一个方面,这种编程方法被称为面向方面编程。

  使用语法糖:

  @logdef now():

  Print(2017_7_28)@符号是装饰器的语法糖,在定义函数时使用,以避免另一次赋值操作。

  这样,我们就可以省略句子now=log(现在)。

  了,直接调用now()即可得到想要的结果。如果我们有其他的类似函数,我们可以继续调用装饰器来修饰函数,而不用重复修改函数或者增加新的封装。这样,我们就提高了程序的可重复利用性,并增加了程序的可读性。

  装饰器在Python使用如此方便都要归因于Python的函数能像普通的对象一样能作为参数传递给其他函数,可以被赋值给其他变量,可以作为返回值,可以被定义在另外一个函数内。

  带参数的装饰器:

  如果decorator本身需要传入参数,那就需要编写一个返回decorator的高阶函数,写出来会复杂一点。比如,要自定义log的文本:

  

def log(text):

   def decorator(func):

   def wrapper(*args,**kw):

   print('%s %s()'%(text,func.__name__))

   return func(*args,**kw)

   return wrapper

   return decorator

这个3层嵌套的decorator用法如下:

  

@log(()

  now()

等价于

  

now = log('goal')(now)
# 首先执行log('execute'),返回的是decorator函数,再调用返回的函数,参数是now函数,返回值最终是wrapper函数
now()
因为我们讲了函数也是对象,它有__name__等属性,但你去看经过decorator装饰之后的函数,它们的__name__已经从原来的'now'变成了'wrapper'

  

print(now.__name__)# wrapper
因为返回的那个wrapper()函数名字就是'wrapper',所以,需要把原始函数的__name__等属性复制到wrapper()函数中,否则,有些依赖函数签名的代码执行就会出错。

  不需要编写wrapper.__name__ = func.__name__这样的代码,Python内置的functools.wraps就是干这个事的,所以,一个完整的decorator的写法如下:

  

import functools

  def log(func):

   @functools.wraps(func)

   def wrapper(*args, **kw):

   print('call %s():' % func.__name__)

   return func(*args, **kw)

   return wrapper

import functools

  def log(text):

   def decorator(func):

   @functools.wraps(func)

   def wrapper(*args, **kw):

   print('%s %s():' % (text, func.__name__))

   return func(*args, **kw)

   return wrapper

   return decorator

类装饰器:

  再来看看类装饰器,相比函数装饰器,类装饰器具有灵活度大、高内聚、封装性等优点。使用类装饰器还可以依靠类内部的__call__方法,当使用 @ 形式将装饰器附加到函数上时,就会调用此方法

  

import time

  class Foo(object):

   def __init__(self, func):

   self._func = func

   def __call__(self):

   print ('class decorator runing')

   self._func()

   print ('class decorator ending')

  @Foo

  def now():

   print (time.strftime('%Y-%m-%d',time.localtime(time.time())))

  now()

总结:

  概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。

  同时在面向对象(OOP)的设计模式中,decorator被称为装饰模式。OOP的装饰模式需要通过继承和组合来实现,而Python除了能支持OOP的decorator外,直接从语法层次支持decorator。Python的decorator可以用函数实现,也可以用类实现。

  更多相关知识请关注python视频教程栏目以上就是Python装饰器详细介绍的详细内容,更多请关注盛行IT软件开发工作室其它相关文章!

  

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: