zoukankan      html  css  js  c++  java
  • python decorator 进阶

      上一篇文章开始的时候提到
       “一般来说,装饰器是一个函数,接受一个函数(或者类)作为参数,返回值也是也是一个函数(或者参数)”
      有一般情况,就有特殊情况。第一种特殊情况:装饰器可能也是一个类;第二种特殊情况:装饰器返回的对象的类型不一定等同于被装饰对象的类型
     
      对于第一种情况,我们知道对于任何callable的对象都可以进行调用(在对象名称后面使用小括号),callable对象的范围就比较广了

    (user-defined functions, built-in functions, methods of built-in objects, class objects, methods of class instances, and certain class instances themselves are callable; extensions may define additional callable object types).

      函数(方法)和类是callable,这个是很好理解的,如果一个类定义了__call__方法,那么该类的实例也是callable。另外,
         @dec
         def func():pass
      等价于: func = dec(func),所以如果dec是一个类,那么dec(func)是合理的,而被装饰后的func就变成了dec类的一个实例,如果dec类定义了__call__, 那么调用func(*)也是合理的,我们来看看修改后的代码
     1 class cost_time_logger(object):
     2     def __init__(self, func):
     3         self.func = func
     4  
     5     def __call__(self, *args, **kwargs):
     6         import time
     7         begin = time.time()
     8         try:
     9             return self.func(*args, **kwargs)
    10         finally:
    11             print('func %s cost %s' % (self.func.__name__, time.time() - begin))
    12  
    13 @cost_time_logger
    14 def complex_func(num):
    15     ret = 0
    16     for i in xrange(num):
    17         ret += i * i
    18     return ret
    19  
    20 if __name__ == '__main__':
    21     print complex_func(100000)
      功能和上一篇文章的code snippet 0是一样的,但是type(complex_func) 变成了 <class '__main__.cost_time_logger'>,这也说明了第二种情况:被装饰的对象原本是函数,被装饰之后变成了一个类实例。
      在pep-0318中,例举了一个用装饰器实现单例的例子,代码如下
     1 def singleton(cls):
     2     instances = {}
     3     def getinstance():
     4         if cls not in instances:
     5             instances[cls] = cls()
     6         return instances[cls]
     7     return getinstance
     8  
     9 @singleton
    10 class MyClass:
    11     pass
    12  
    13 if __name__ == '__main__':
    14     print type(MyClass)
      MyClass被装饰前是一个类,被装饰后变成了一个function。
     
      笔者不是很喜欢这种改变被装饰对象的类型的实现方法,这种实现对代码的阅读者不是很友好,而且可能产生一些莫名其妙的BUG,浪费debug的时间。对于单例的例子,stackoverflow上也有其他的实现。
     
    references:
  • 相关阅读:
    js比较两个String字符串找出不同,并将不同处高亮显示
    C# 去掉webapi返回json所带的转义字符
    .Net C#向远程服务器Api上传文件
    Access-Control-Allow-Origin,跨域
    ajax时间戳或随机数
    SqlServer收缩日志文件
    MsDepSvc 启动失败
    SqlServer收缩数据库语句
    sql server datetime类型字段使用isnull返回1900-01-01 00:00:00.000的问题
    EXCEPTION与ERROR的区别
  • 原文地址:https://www.cnblogs.com/xybaby/p/6274283.html
Copyright © 2011-2022 走看看