博客
关于我
Python:函数 ----》装饰器函数
阅读量:342 次
发布时间:2019-03-04

本文共 4752 字,大约阅读时间需要 15 分钟。

目录


 

引入

一个加法函数,想增强它的功能,能够输出被调用过以及调用的参数信息

def add(x, y):    return x + y

用嵌套函数、柯里化来解决

def add(x,y):    return x + ydef logger(fn):    def _loger(*args,**kwargs):        print("函数开始运行")        ret = fn(*args,**kwargs)        print("函数结束")        return ret    return _logerprint(logger(add)(10,40))

在变形【这就是装饰器函数,侵入式代码】

  • 装饰器语法糖
def logger(fn):    def _loger(*args,**kwargs):        print("函数开始运行")        ret = fn(*args,**kwargs)        print("函数结束")        return ret    return _loger@logger    #等价于 add1 = logger(add1)  def add1(x,y):     return x + y#add1 = logger(add1) print(add1(5,10))

 

 装饰器【无参】

装饰器(无参)

  • 它是一个函数
  • 函数作为它的形参
  • 返回值也是一个函数
  • 可以使用@functionname方式,简化调用方式

装饰器和高阶函数

  • 装饰器是高阶函数,但装饰器是对传入函数的功能的装饰(功能增强)

文档字符串 

Python的文档

  • Python是文档字符串Documentation Strings
  • 在函数语句块的第一行,且习惯是多行的文本,所以多使用三引号
  • 惯例是首字母大写,第一行写概述,空一行,第三行写详细描述
  • 可以使用特殊属性__doc__访问这个文档

只能放在番薯的第一行,否则无法获取到,显示为None

 

def add(x,y):    """    This a funation add    :param x:    :param y:    :return:    """    return x + yprint("name={},\ndoc={}".format(add.__name__,add.__doc__))name=add,doc=    This a funation add    :param x:    :param y:    :return:

怎样才能使用,@logger装饰器的函数之后,显示add原函数的doc文档信息??

 

def logger(fn):    def _loger(*args,**kwargs):        "This funation logger"        print("函数开始运行")        ret = fn(*args,**kwargs)        print("函数结束")        return ret    return _loger@loggerdef add(x,y):    '''    This is funation add    '''    return x + yprint(add.__name__,add.__doc__)结果:_loger This funation logger

变法一:自己编写函数去实现

  • 通过copy_properties函数将被包装函数的属性覆盖掉包装函数
  • 凡是被装饰的函数都需要复制这些属性,这个函数很通用
  • 可以将复制属性的函数构建成装饰器函数,带参装饰器
def copy_doc(src,dst):    dst.__name__ = src.__name__    dst.__doc__ = src.__doc__def logger(fn):    def loger(*args,**kwargs):        "This funation logger"        print("函数开始运行")        ret = fn(*args,**kwargs)        print("函数结束")        return ret    copy_doc(fn,loger)    return loger@loggerdef add(x,y):    '''    This is funation add    '''    return x + yprint(add(3,6),add.__name__,add.__doc__)结果:函数开始运行函数结束9 add     This is funation add

变法二:进一步改变为装饰器函数

def copy_doc(src):    def _copy(dst):        dst.__name__ = src.__name__        dst.__doc__ = src.__doc__        return dst    return _copydef logger(fn):    @copy_doc(fn)   #copy_doc(fn,loger)    def loger(*args,**kwargs):        "This funation logger"        print("函数开始运行")        ret = fn(*args,**kwargs)        print("函数结束")        return ret    return loger@loggerdef add(x,y):    '''    This is funation add    '''    return x + yprint(add(3,6),add.__name__,add.__doc__)结果:函数开始运行函数结束9 add     This is funation add

 

带参装饰器

带参装饰器

  • 函数作为它的形参
  • 返回值是一个不带参的装饰器函数
  • 使用@functionname(参数列表)方式调用
  • 可以看做在装饰器外层又加了一层函数

例子:计算函数运行行多长时间

import datetimeimport timedef logger(fn):    def wrap(*args, **kwargs):        # before 功能增强        print("args={}, kwargs={}".format(args,kwargs))        start = datetime.datetime.now()        ret = fn(*args, **kwargs)        # after 功能增强        duration = (datetime.datetime.now()-start).total_seconds()        print("function {} took {}s.".format(fn.__name__, duration))        return ret    return wrap@logger # 相当于 add = logger(add)def add(x, y):    print("===call add===========")    time.sleep(2)    return x + yprint(add(4, y=7))结果:args=(4,), kwargs={'y': 7}===call add===========function add took 2.007478s.11

上面的例子,不够灵活,如果我们计算,大于3秒,小于5秒的函数,改怎么来改

  • 时间自己来控制
import datetimeimport timedef logger(t1,t2):    def t_time(fn):        def wrap(*args, **kwargs):            # before 功能增强            print("args={}, kwargs={}".format(args,kwargs))            start = datetime.datetime.now()            ret = fn(*args, **kwargs)            # after 功能增强            duration = (datetime.datetime.now()-start).total_seconds()            if duration >t1 and duration < t2:                print("function {} took {}s.".format(fn.__name__, duration))            return ret        return wrap    return t_time@logger(3,5) # 相当于 add = logger(add)def add(x, y):    print("===call add===========")    time.sleep(4)    return x + yprint(add(4, y=7))结果:args=(4,), kwargs={'y': 7}===call add===========function add took 4.002905s.11

总结

最难的装饰器也就是上面个这个样子了 

将记录的功能提取出来,这样就可以通过外部提供的函数来灵活的控制输出

import datetimedef copy_doc(src):    def _copy(dst):        dst.__name__ = src.__name__        dst.__doc__ = src.__doc__        return dst    return _copydef logger(duration, func=lambda name, duration: print('{} took {}s'.format(name, duration))):    def _logger(fn):        @copy_doc(fn) # wrapper = wrapper(fn)(wrapper)        def wrapper(*args,**kwargs):            start = datetime.datetime.now()            ret = fn(*args,**kwargs)            delta = (datetime.datetime.now() - start).total_seconds()            if delta > duration:                func(fn.__name__, duration)            return ret        return wrapper    return _logger

 

转载地址:http://dzre.baihongyu.com/

你可能感兴趣的文章
算法学习笔记: 珂朵莉树
查看>>
算法学习笔记:母函数详解
查看>>
Codeforces Round #664 题解(A ~ C)
查看>>
Problem 1342B - Binary Period (思维)
查看>>
Problem A - Sequence with Digits (数学推导)
查看>>
Problem 330A - Cakeminator (思维)
查看>>
Codeforces Round #674 (Div. 3) (A - F题题解)
查看>>
「HDU-2196」Computer (树形DP、树的直径)
查看>>
Codeforces Global Round 11 个人题解(B题)
查看>>
LeetCode75 颜色分类 (三路快排C++实现与应用)
查看>>
GDB调试基础使用方法
查看>>
Codeforces 1092C Prefixes and Suffixes【字符串+思维】
查看>>
HHKB 键盘布局记录以及一些闲言碎语
查看>>
AIsing Programming Contest 2020 游记 (ABC水题,D思维)
查看>>
【译】N 皇后问题 – 构造法原理与证明 时间复杂度O(1)
查看>>
docker基础:容器生命周期管理命令
查看>>
Shell脚本学习指南
查看>>
日志切分神器--logrotate
查看>>
C#3.0新增功能08 Lambda 表达式
查看>>
C#开发BIMFACE系列35 服务端API之模型对比6:获取模型构建对比分类树
查看>>