Python:函数 ----》装饰器函数
发布日期:2021-05-07 14:08:01 浏览次数:7 分类:原创文章

本文共 4755 字,大约阅读时间需要 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

 

上一篇:Python:funtools模块、覆盖被装饰的函数模块名、名称、限定名、文档、参数注解
下一篇:Python:高阶函数,柯里化Currying

发表评论

最新留言

初次前来,多多关照!
[***.217.46.12]2025年04月05日 02时27分13秒