Python-02进阶-02装饰器

Python-00装饰器

装饰器

[toc]

TODO

总结

装饰器的作用就是为已经存在的函数或对象添加额外的功能

装饰器使用种类:

  • 函数装饰器
  • 类装饰器
  • 函数装饰器装饰 类
  • 类装饰器装饰 函数

装饰器样例

@staticmethod
@logging
def a():
    return 1
    pass
等价于
a = staticmethod(logging(a)) 

默认装饰器函数

  • @property
    通过property装饰器控制类的属性的绑定与获取,一般就是给某个属性增加一个验证类型等功能。
  • @staticmethod
    将被装饰的函数从类中分离出来,该函数不能访问类的属性,简单说可以将该函数理解为一个独立的函数,不允许使用self。
    staticmethod 就是将该被装饰的函数与该类没有关系,该函数不能用self传参,需要和普通函数一样传参。
  • @classmethod
    classmethod 可以用来为一个类创建一些预处理的实例.类方法只能找类变量,不能访问实例变量

装饰器库 functools
因为使用装饰器 functools 会导致函数或类信息缺失。
例如 func.__name__
所以需要使用 functools 装饰器库处理

使用方法:
每个装饰器前面加上下句话即可
@functools.wraps(func)
样例如下所示:

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

装饰器&函数

函数简单说明

参考链接: 12步轻松搞定python装饰器

了解装饰器之前也需要了解内部函数与函数闭包

参考链接: 内部函数&函数闭包

内部函数

def wai_hanshu(canshu_1):

  def nei_hanshu(canshu_2): # 我在函数内部有定义了一个函数
    return canshu_1*canshu_2

  return nei_hanshu  # 我将内部函数返回出去

a = wai_hanshu(123)   # 此时 canshu_1 = 123
print a
print a(321)  # canshu_2 = 321

闭包说明
参考链接: 函数闭包
python中的闭包从表现形式上定义(解释)为:
如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure)。

  • 闭包=函数+引用环境
  • 闭包中是不能修改外部作用域的局部变量的
  • 当闭包执行完后,仍然能够保持住当前的运行环境
  • 闭包可以根据外部作用域的局部变量来得到不同的结果

装饰器说明

装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能
装饰器的返回值也是一个函数对象。
它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。
装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。

装饰器的作用就是为已经存在的函数或对象添加额外的功能

装饰器/修饰符 - decorator

装饰器知识

函数装饰器

参考链接:
https://www.cnblogs.com/cicaday/p/python-decorator.html

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

简单装饰器样例

def debug(func):
    def wrapper(*args, **kwargs):  # 指定宇宙无敌参数
        print "[DEBUG]: enter {}()".format(func.__name__)
        print 'Prepare and say...',
        return func(*args, **kwargs)
    return wrapper  # 返回

@debug
def say(something):
    print "hello {}!".format(something)
   
等同于 
say = debug(say)

原理分析

@decorator_a
def f():
    pass
等价于
f = decorator_a(f)

装饰器满足的条件

  1. 装饰器函数运行在函数定义的时候
  2. 装饰器需要返回一个可执行的对象
  3. 装饰器返回的可执行对象要兼容函数f的参数

类装饰器

类装饰器中必须使用 __call__ 方法。将类实例转为可调用对象。

class Decorator(object):
    def __init__(self, f):
        self.f = f
    def __call__(self):
        print("decorator start")
        self.f()
        print("decorator end")

@Decorator
def func():
    print("func")

func()

这里有注意的是:call()是一个特殊方法,它可将一个类实例变成一个可调用对象:

p = Decorator(func) # p是类Decorator的一个实例
p() # 实现了__call__()方法后,p可以被调用

要使用类装饰器必须实现类中的call()方法,就相当于将实例变成了一个方法。

装饰器链

所谓装饰器链,即多个装饰器的解析方式。

@decorator_b
@decorator_a
def test():
    pass
等同于
test = decorator_b(decorator_a(test))

装饰器执行顺序 是从近到远依次执行

内置装饰器

内置装饰器

  • 特性(property)
  • 静态方法(staticmethod)
  • 类方法(classmethod)

内置装饰器参考链接

附录A-装饰器库参数表

官方functools文档
functools参考博客

functools,用于高阶函数:
指那些作用于函数或者返回其它函数的函数,通常只要是可以被当做函数调用的对象就是这个模块的目标。

functools方法

  • cmp_to_key,将一个比较函数转换关键字函数;
  • partial,针对函数起作用,并且是部分的;
  • reduce,与python内置的reduce函数功能一样;
  • total_ordering,在类装饰器中按照缺失顺序,填充方法;
  • update_wrapper,更新一个包裹(wrapper)函数,使其看起来更像被包裹(wrapped)的函数;
  • wraps,可用作一个装饰器,简化调用update_wrapper的过程;

cmp_to_key
将老式的比较函数(comparison function)转换为关键字函数(key function),与接受key function的工具一同使用(例如sorted,min,max,heapq.nlargest,itertools.groupby),该函数主要用于将程序转换成Python 3格式的,因为Python 3中不支持比较函数。比较函数是可调用的,接受两个参数,比较这两个参数并根据他们的大小关系返回负值、零或者正值中的一个。关键字函数也是可调用的,接受一个参数,同时返回一个可以用作排序关键字的值。
partial
functools.partial(func, *args, **keywords),函数装饰器,返回一个新的partial对象。调用partial对象和调用被修饰的函数func相同,只不过调用partial对象时传入的参数个数通常要少于调用func时传入的参数个数。
reduce
与Python内置的reduce函数一样,为了向Python3过渡
total_ordering
这是一个类装饰器,给定一个类,这个类定义了一个或者多个比较排序方法,这个类装饰器将会补充其余的比较方法,减少了自己定义所有比较方法时的工作量.
被修饰的类必须至少定义 lt(), le(),gt(),ge()中的一个,同时,被修饰的类还应该提供 eq()方法。
update_wrapper
更新一个包裹(wrapper)函数,使其看起来更像被包裹(wrapped)的函数。
wraps
这个函数可用作一个装饰器,简化调用update_wrapper的过程,调用这个函数等价于调用partial(update_wrapper, wrapped = wrapped, assigned = assigned,updated = updated)。

附录B-测试代码样例

文件: /home/scfan/pro/server/pro/tools/base_decorator.py

import time
import datetime
import functools

def decorator_func(text="all"):
    u""" 统计函数相关信息 All
    - 函数运行时间
    - 函数名称

    """
    def decorator(func,*args,**kwargs):
        @functools.wraps(func)
        def wrapper(*args,**kwargs):
            start = datetime.datetime.now()
            data = func(*args, **kwargs)
            runtime = datetime.datetime.now() - start
            msg = "@函数运行信息: 函数类型[%s],函数名称[%s],运行时间[%s秒]"%(text,func.__name__,runtime.total_seconds())
            print(msg)
            return data
        return wrapper
    return decorator

class Decorator(object):
    u"""
        装饰器类
    """
    def __init__(self, func):
        self.func = func

    # __call__()是一个特殊方法,它可将一个类实例变成一个可调用对象
    def __call__(self, *args, **kwargs):
        print("decorator start")
        self.func()
        print("decorator end")
 
 if __name__ == '__main__':
    @Decorator
    @decorator_func("all")
    def a(b="cc"):
        for i in range(2):
            time.sleep(1)
        print "函数运行...."
        return b
    a()      

运行信息

(env) [scfan@WOM tools]$ python base_decorator.py 
decorator start
函数运行....
@函数运行信息: 函数类型[all],函数名称[a],运行时间[2.004331秒]
decorator end

附录C-参考资源链接

附录D-装饰器相关

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,907评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,987评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,298评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,586评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,633评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,488评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,275评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,176评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,619评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,819评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,932评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,655评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,265评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,871评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,994评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,095评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,884评论 2 354

推荐阅读更多精彩内容