• Python装饰器


    装饰器本质上是一个 Python 函数或类,它可以让其他函数或类在不需要做任何代码修改的前提下增加额外功能,装饰器的返回值也是一个函数/类对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景,装饰器是解决这类问题的绝佳设计。有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码到装饰器中并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。装饰器(decorator) 是一个返回函数的高阶函数(把函数作为参数传入,这样的函数称为高阶函数),装饰器在Python中如此方便都要归因于Python的函数可以像普通的函数一样能作为参数。传递给其他函数,可以被赋值给其他变量,可以作为返回值,可以被定义在另外一个函数内,函数进入和退出时 ,被称为一个横切面,这种编程方式被称为面向切面的编程。在java中也有这个概念。

    例如:
    @user_logging
    def log():
    print("log")
    上面的过程简单的来说就类似于bar = user_logging(bar),就相当于把bar放入user_logging中处理一番,再返回赋值给bar,这样bar就被user_logging装饰了。@其实就是python中提供的语法糖,我们不需要每次都采用bar = user_logging(bar)这种方式,直接使用@就可以了。
    普通的装饰器

    def log(func):
        def wrapper(*args, **kw):
            print('call %s():' % func.__name__)
            return func(*args, **kw)
        return wrapper
    @log
    def now():
        print('2018-1-21')

    结果如下:

    now()
    call now():
    2018-1-21

     带参数的装饰器 

    def log(text):
        def decorator(func):
            def wrapper(*args, **kw):
                print('%s %s():' % (text, func.__name__))
                return func(*args, **kw)
            return wrapper
        return decorator
    @log('execute')
    def now():
        print('2018-01-21')

     结果如下:

    now()
    execute now():
    2018-01-21

    使用装饰器极大的复用了代码。但是他有一个缺点就是原函数的元信息不见了,主要函数被装饰后一些属性变为装饰器的属性了,比如__name__ __doc__等等。好在我们有functools.wraps这个装饰器,他能把原函数的元信息拷贝到装饰器函数中 如果有多层嵌套 那么 functools.wraps 应该加在最里面一个装饰器函数前面。

    import functools
    
    def log(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            print('call %s():' % func.__name__)
            return func(*args, **kw)
        return wrapper

    装饰器调用顺序 装饰器是可以叠加使用的,那么就存在一个调用先后顺序,这里面是deco_2先调用再调用deco_1
    例如:
    @deco_1
    @deco_2
    def addFunc(a,b):
    print("ccd")

    类装饰器

    装饰器不仅可以是函数,还可以是类,相比函数装饰器,类装饰器具有灵活度大、高内聚、封装性等优点。如果希望让一个类变成装饰器,就需要定义它的__call__方法,因为这里进行类似于这样的处理:bar= Foo(bar),所以需要将类变为可调用的,需要定义
    它的__call__方法,对于类x提供了__call__,则x(arg1,arg2,..)就等同于x.__call__(arg1,arg2,....)

    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 bar():
        print ('bar')

    bar()

     结果:

    class decorator runing
    bar
    class decorator ending
  • 相关阅读:
    获取Enum枚举值描述的几法方法
    Android开发入门 Button事件实现的方法(原创)
    最有价值的.Net第三方控件
    Eclipse快捷键大全(转载)
    recovery教程
    XP系统通过无线网卡共享宽带给其他设备,正确的共享设置(修正版,绝对可行)
    使用Eclipse写QT
    Android 4.0模拟器弹出“谷歌拼音输入法”已停止运行的解决方法
    C# 枚举用法总结
    谷歌安卓系统使用必读,什么是root, Recovery, Radio, APP TO SD, Rom
  • 原文地址:https://www.cnblogs.com/BGPYC/p/8324757.html
Copyright © 2020-2023  润新知