17.装饰器

作者: Stone_説 | 来源:发表于2020-12-25 12:52 被阅读0次

1.装饰器介绍

add函数

>>> def add(x,y):
...     return x+y
>>> print(add(4,4))
8

变式一:增加打印日志到控制台

>>> def add(x,y):
...     print("call add,x+y")
...     return x+y
>>> print(add(4,4))
call add,x+y
8

变式二:解决变式一耦合度太高问题

>>> def add(x,y):
...     return x+y
>>> def logger(fn):
...     print('begin')
...     ret = fn(4,5)
...     print('end')
...     return ret
>>> print(logger(add))
begin
end
9

变式三:解决变式二传参传递问题

>>> def add(x,y):
...     return x+y
>>> def logger(fn,*args,**kwargs):
...     print("begin")
...     ret = fn(*args,**kwargs)
...     print("end")
...     return ret
>>> print(logger(add,5,y=100))
begin
end
105

变式四:解决变式三中logger函数进行柯里化

>>> def add(x,y):
...     return x+y
>>> def logger(fn):
...     def wrapper(*args,**kwargs):
...             print('begin')
...             ret = fn(*args,**kwargs)
...             print('end')
...             return ret
...     return wrapper
>>> print(logger(add)(11,y=24))
begin
end
35
>>> add = logger(add)  # 如果使用这一个赋值方式,需要在add函数和logger函数调用完成之后才可以
>>> add(11,y=45)
begin
end
56

变式五:装饰器的语法,@functionname

>>> @logger
... def add(x,y):
...     return x+y
... 
>>> add(55,55)
begin
end
110

装饰器语法:

一个装饰器就是一个函数,它接受一个函数作为参数并返回一个新的函数。
可以使用@functionname方式,简化调用
装饰器就是一个高阶函数,但装饰器是对传入函数的功能的装饰(功能增强)

2.装饰器的应用(一)

统计函数运行时间

[root@node05 python]# vim test2.py
import datetime
import time

def 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
        print("function {}took {}s.".format(fn.__name__,duration.total_seconds()))
        return ret
    return wrap

@logger
def add(x,y):
    print("===call add===")
    time.sleep(2)
    return x+y

print(add(5,y=100))
[root@node05 python]# python3 test2.py
args=(5,),kwargs={'y': 100}
===call add===
function addtook 2.002801s.
105

3.创建装饰器时保留函数的元信息

>>> def logger(fn):
...     def wrapper(*args,**kwargs):
...             'I am wrapper'
...             print('begin')
...             x = fn(*args,**kwargs)
...             print('end')
...             return x
...     return wrapper
>>> @logger
... def add(x,y):
...     """This is a function for add"""
...     return x+y
>>> print("name={},doc={}".format(add.__name__,add.__doc__))
name=wrapper,doc=I am wrapper

变式1:提供一个copy_properties函数,包装本封装函数属性

通过copy_properties函数将被包装函数的属性覆盖掉包装函数
凡是被装饰的函数都需要复制这些属性,这个函数必须要通用
可以将复制属性的函数构建成装饰器函数,带参装饰器
[root@node05 python]# vim test3.py
def copy_properties(dst,src):
    dst.__name__ = src.__name__
    dst.__doc__ = src.__doc__
    
def logger(fn):
    def wrapper(*args,**kwargs):  # wrapper包装函数
        """I am wrapper"""
        print('begin')
        x = fn(*args,**kwargs)  # fn称为被包装函数
        print('end')
        return x
    # def copy_properties(dst,src):
        # dst.__name__ = src.__name__
        # dst.__doc__ = src.__doc__
    copy_properties(wrapper,fn)
    return wrapper

@logger
def add(x,y):
    """This is a function for add"""
    return x+y

print("name = {},doc={}".format(add.__name__,add.__doc__))

[root@node05 python]# python3 test3.py
name = add,doc=This is a function for add

变式2:将copy_properties函数柯里化,并改造成带参装饰器
这里需要把copy_properties函数的src和dst顺序进行修改,更加便于改写为带参装饰器

[root@node05 python]# vim test3.py
def copy_properties(src):
    def _copy(dst):
        dst.__name__ = src.__name__
        dst.__doc__ = src.__doc__
        return dst
    return _copy
    
def logger(fn):
    @copy_properties(fn)     # wrapper = copy_properties(fn)(wrapper)
    def wrapper(*args,**kwargs):  # wrapper包装函数
        """I am wrapper"""
        print('begin')
        x = fn(*args,**kwargs)  # fn称为被包装函数
        print('end')
        return x
    return wrapper

@logger
def add(x,y):
    """This is a function for add"""
    return x+y

print("name = {},doc={}".format(add.__name__,add.__doc__))

[root@node05 python]# python3 test3.py
name = add,doc=This is a function for add

4.装饰器的应用(二)

获取函数执行时长,对时长超过阈值的函数进行记录

[root@node05 python]# vim test2.py 
import datetime
import time

def copy_properties(src):
    def _copy(dst):
        dst.__name__ = src.__name__
        dst.__doc__ = src.__doc__
        return dst
    return _copy

def logger(duration):
    def _logger(fn):
        @copy_properties(fn) # wrapper = wrapper(fn)(wrapper)
        def wrapper(*args,**kwargs):
            start = datetime.datetime.now()
            ret = fn(*args,**kwargs)
            delta = (datetime.datetime.now() - start).total_seconds()
            print('so slow') if delta > duration else print('so fast')
            return ret
        return wrapper
    return _logger


@logger(5) # add = logger(5)(add)
def add(x,y):
    time.sleep(3)
    return x + y

[root@node05 python]# python3 test2.py 
so fast
11

5.带参装饰器

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

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

def copy_properties(src):
    def _copy_properties(dst):
        dst.__name__ = src.__name__
        dst.__doc__ = src.__doc__
        return dst
    return _copy_properties

def logger(duration,func=lambda name,delta:print('{} took {:2f}s'.format(name,delta))):
    def _logger(fn):
        @copy_properties(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__,delta)
            return ret
        return wrapper
    return _logger

@logger(5)
def add(x,y):
    time.sleep(7)
    return x + y

print(add(4,5))

#  程序运行结果
add took 7.000445s
9

相关文章

  • 17.装饰器

    1.装饰器介绍 add函数 变式一:增加打印日志到控制台 变式二:解决变式一耦合度太高问题 变式三:解决变式二传参...

  • 装饰器

    """@装饰器- 普通装饰器- 带参数的装饰器- 通用装饰器- 装饰器装饰类- 内置装饰器- 缓存装饰器- 类实现...

  • typescript 五种装饰器

    装饰器类型 装饰器的类型有:类装饰器、访问器装饰器、属性装饰器、方法装饰器、参数装饰器,但是没有函数装饰器(fun...

  • python——装饰器详解

    一、装饰器概念 1、装饰器 装饰器:一种返回值也是一个函数的函数,即装饰器。 2、装饰器目的 装饰器的目的:装饰器...

  • Python装饰器

    Python装饰器 一、函数装饰器 1.无参装饰器 示例:日志记录装饰器 2.带参装饰器 示例: 二、类装饰器 示例:

  • Python中的装饰器

    Python中的装饰器 不带参数的装饰器 带参数的装饰器 类装饰器 functools.wraps 使用装饰器极大...

  • 装饰器

    装饰器 decorator类装饰器 带参数的装饰器 举例(装饰器函数;装饰器类;有参与无参) https://fo...

  • TypeScript装饰器

    前言 装饰器分类 类装饰器 属性装饰器 方法装饰器 参数装饰器需要在tsconfig.json中启用experim...

  • python之装饰器模版

    装饰器的作用:装饰器即可以装饰函数也可以装饰类。装饰器的原理:函数也是对象 1.定义装饰器 2.使用装饰器假设de...

  • 装饰器实验

    装饰器实验 说明 ts内包含了四个装饰器,类装饰器、属性装饰器、函数装饰器、参数装饰器,本文中测试一下其的使用。 ...

网友评论

    本文标题:17.装饰器

    本文链接:https://www.haomeiwen.com/subject/hwrcnktx.html