Python-02进阶-02装饰器

Python-00装饰器

装饰器


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-装饰器相关

posted @ 2020-02-01 22:51  SuperScfan  阅读(183)  评论(0编辑  收藏  举报