python函数装饰器用法分解示例


声明:本文转载自https://my.oschina.net/watcher/blog/1551500,转载目的在于传递更多信息,仅供学习交流之用。如有侵权行为,请联系我,我会及时删除。

我们将通过举例一个小函数,通过使用装饰器增加功能(实现方法不一定最好,这里仅仅是为了说明装饰器用法,不要钻牛角尖)。

1.最简单的函数

这是一个最简单的函数,打印这个计算的结果和开始结束时间(此处计算量很小,几乎同时完成,所以开始结束时间一样没有关系)

源码

# coding: utf-8 import time  def do():     print 'start:', time.time()      result = 1 + 1     print 'result:', result      print 'end:', time.time()  do() 

输出

start: 1508143969.67 result: 2 end: 1508143969.67 

2.使用装饰器增加功能,打印函数执行开始和结束时间

在python中,函数是可以作为参数传递给另一个函数的。装饰器其实就是以一个函数为参数的普通函数,然后又返回一个函数。 请注意此例的注释和执行结果

  1. 包装器接受一个函数作为参数,又返回一个新的函数
  2. 包装的过程是在程序启动时就执行的,直接返回了新函数替换了def处的函数,并非等到执行do()才替换该函数

源码

# coding: utf-8 import time   def print_run_time(func):   # 接受一个函数作为参数     def wrapper():  # 构造的新的函数,用于返回替换函数func         print 'start:', time.time()         func()         print 'end:', time.time()     return wrapper  # 注意没有后缀(),因为要返回构造的新函数,而不是新函数调用结果   def do():     result = 1 + 1     print 'result:', result  print u'调用原始的do函数:' do()  print u'根据装饰器的定义手动调用,用装饰器包装do函数:' print_run_time(do)()  print u'根据装饰器的定义手动调用,用装饰器包装do函数(分步骤调用,思考整个调用过程和原理):' new_do = print_run_time(do)     # 把do函数作为参数,注意do没有后缀() print u'装饰器返回一个函数', type(new_do) new_do()    # 调用装饰后的新函数 

输出

调用原始的do函数: result: 2 根据装饰器的定义手动调用,用装饰器包装do函数: start: 1508145089.23 result: 2 end: 1508145089.23 根据装饰器的定义手动调用,用装饰器包装do函数(分步骤调用,思考整个调用过程和原理): 装饰器返回一个函数 <type 'function'> start: 1508145089.23 result: 2 end: 1508145089.23 

3.使用语法糖包装函数

@语法糖相当于new_do = print_run_time(do)

源码

# coding: utf-8 import time   def print_run_time(func):     def wrapper():         print 'start:', time.time()         func()         print 'end:', time.time()     return wrapper   @print_run_time def do():     result = 1 + 1     print 'result:', result  do() 

输出

start: 1508145584.21 result: 2 end: 1508145584.21 

4.包装带参数的函数

do函数改为需要输入x,y然后计算结果

源码

# coding: utf-8 import time   def print_run_time(func):     def wrapper(x, y, *args, **kwargs):     # wrapper为构造的新函数,那么原来func的参数都被传递给了wrapper          print 'start:', time.time()         func(x, y, *args, **kwargs)         print 'end:', time.time()     return wrapper   @print_run_time def do(x, y):     result = x + y     print 'result:', result  do(1, 2) 

输出

start: 1508145970.8 result: 3 end: 1508145970.8 

5.带参数的装饰器

之前输出的时间是时间戳,现在我们要根据装饰器的参数来决定打印时间戳或者日期时间。 这就需要一个工厂函数(根据参数创建一个装饰器,然后再去包装原始的do函数),原理同以上将的装饰器,不再赘述,仔细对比代码变化即可

源码

# coding: utf-8 import time, datetime   def print_run_time(time_type):  # 多了这一层来根据参数创建一个装饰器     def wrapper_factory(func):      # 根据参数构造的装饰器         def wrapper(x, y, *args, **kwargs):             if time_type == 'datetime':                 print 'start:', datetime.datetime.now()                 func(x, y, *args, **kwargs)                 print 'end:', datetime.datetime.now()             else:                 print 'start:', time.time()                 func(x, y, *args, **kwargs)                 print 'end:', time.time()          return wrapper     return wrapper_factory   @print_run_time('datetime') def do(x, y):     result = x + y     print 'result:', result  do(1, 2) 

输出

start: 2017-10-16 17:37:25.286000 result: 3 end: 2017-10-16 17:37:25.286000 

6.带参数的装饰器(使用类的__call__

以上带参数装饰器使用工厂函数,多了一层更加使人迷惑,其实原理不变,这里把装饰器工厂函数用类来实现更加清晰明了

源码

# coding: utf-8 import time, datetime   class print_run_time:     def __init__(self, time_type):  # 装饰器参数         self.time_type = time_type      # __call__使实例变为可调用对象,相当于一个函数     def __call__(self, func):         def wrapper(x, y, *args, **kwargs):             if self.time_type == 'datetime':                 print 'start:', datetime.datetime.now()                 func(x, y, *args, **kwargs)                 print 'end:', datetime.datetime.now()             else:                 print 'start:', time.time()                 func(x, y, *args, **kwargs)                 print 'end:', time.time()          return wrapper   @print_run_time('datetime') def do(x, y):     result = x + y     print 'result:', result   do(1, 2) 

输出

start: 2017-10-16 17:45:04.094000 result: 3 end: 2017-10-16 17:45:04.094000 

本文发表于2017年10月16日 18:39
(c)注:本文转载自https://my.oschina.net/watcher/blog/1551500,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如有侵权行为,请联系我们,我们会及时删除.

阅读 1781 讨论 0 喜欢 0

抢先体验

扫码体验
趣味小程序
文字表情生成器

闪念胶囊

你要过得好哇,这样我才能恨你啊,你要是过得不好,我都不知道该恨你还是拥抱你啊。

直抵黄龙府,与诸君痛饮尔。

那时陪伴我的人啊,你们如今在何方。

不出意外的话,我们再也不会见了,祝你前程似锦。

这世界真好,吃野东西也要留出这条命来看看

快捷链接
网站地图
提交友链
Copyright © 2016 - 2021 Cion.
All Rights Reserved.
京ICP备2021004668号-1