Python装饰器

装饰器

装饰器(无参)

  • 它是一个函数
  • 函数作为它的形参。无参装饰器实际上就是一个单形参函数
  • 返回值也是一个函数
  • 可以使用@functionname方式,简化调用

装饰器和高阶函数

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

打印日志装饰器写法

def logger(fn): # fn = (lambada x,y:x+y) # logger 记录
    def wrapper(*args,**kwargs): # (4, 5) # wrapper 包装
        print('before') # 函数之前功能增强
        print("add function:{}|{}".format(args,kwargs))
        ret = fn(*args,**kwargs) #(lambda x,y:x+y)(4, 5)
        print('after',ret) # 函数之后功能增强
        return  ret
    return wrapper

@logger # add = logger(add)
def add(x,y): # 完成加法功能的函数 add = lambda x,y:x + y
    return x + y

add(4,5)
  • 打印结果
before
add function:(4, 5)|{}
after 9

获取函数的执行时长

import datetime
import time
def logger(fn):
    def wrapper(*args,**kwargs):
        print('begin to work')
        start = datetime.datetime.now() # 开始时间
        ret = fn(*args,**kwargs)
        delta = (datetime.datetime.now() - start).total_seconds() # add代码运行总时长
        print('{} took {:.2f}s'.format(fn.__name__,delta)) # 打印时长,{:.2f}保留小数点后两位
        return ret
    return wrapper

@logger
def add(x,y):
    time.sleep(2) # 使函数运行时休眠两秒
    return x + y

add(40,50)
  • 打印结果
begin to work
add took 2.00s

获取函数时长,对时长超过阀值的函数记录一下

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

print(add(5,6))

  • 打印结果
so fast
11

文档字符串

Python的文档

  • Python文档字符串Documentation Strings
  • 在函数语句块的第一行,且习惯是多行的文本,所以多使用三引号
  • 惯例是首字母大写,第一行写概述,空一行,第三行写详细描述
  • 可以使用特殊属性__doc__访问这个文档
def add(x,y):
    """This is a function of addition"""
    return x + y

print("name={}\ndoc={}".format(add.__name__,add.__doc__))
print(help(add))
  • 打印结果
name=add
doc=This is a function of addition
Help on function add in module __main__:

add(x, y)
    This is a function of addition

None

还原函数名称与属性

  • 通过copy_properties函数将被包装函数的属性覆盖掉包装函数
  • 凡是被装饰的函数都需要复制这些属性,这个函数很通用
  • 可以将复制属性的函数构建成装饰器函数,带参装饰器
def copy_properties(src): # src = fn
    def _copy(dst): # dst = wrapper
        dst.__name__ = src.__name__
        dst.doc__ = src.__doc__
        return dst # 相当于返回的 wrapper
    return _copy

def logger(fn):
    @copy_properties(fn) # wrapper = copy_properties(fn)(wrapper)
    def wrapper(*args,**kwargs):
        """I am wrapper"""
        print('begin')
        x = fn(*args,**kwargs)
        print('end')
        return x
    return wrapper

@logger
def add(x,y): # add = logger(add)
    """This is a function for add"""
    return x + y
print("name={},doc={}".format(add.__name__,add.__doc__))
  • 打印结果,因调用了@copy_properties,所以add的名称和属性还是原来的
name=add,doc=I am wrapper 

带参装饰器

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

functools模块

functools.update_wrapper(wrapper,wrapped,assigned=WRAPPER_ASSIGNMENTS,updated=WRAPPER_UPDATES)

  • 类似copy_properties功能
  • wrapper 包装函数、被更新者,wrapped被包装函数、数据源
  • 元祖WRAPPER_ASSIGNMENTS中是要被覆盖的属性
  • 模块名__module__,名称__name__,限定名__qualname__,文档__doc__,参数注解__annotations__
  • 元祖WRAPPER_UPDATES中要是被更新的属性,__dict__属性字典
  • 增加一个__wrapped__属性,保留着wrapped函数

from functools import update_wrapper,wraps

import datetime
import time
import functools
from functools import update_wrapper,wraps

def logger(durantion):
    def _logger(fn):
        @wraps(fn) # wrapper = upadte_wrapper(fn)(wrapper)
        def wrapper(*args,**kwargs):
            '''My name is wrapper'''
            start = datetime.datetime.now()
            ret = fn(*args,**kwargs)
            delta = (datetime.datetime.now() - start).total_seconds()
            print('so slow') if delta > durantion else print('so fast')
            return ret
        # update_wrapper(wrapper, fn) # 等同上面 @wraps
        return wrapper
    return _logger

@logger(5)
def add(x,y):
    '''This is a function of addition'''
    time.sleep(1)
    return x + y

print(add.__name__,add.__doc__)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值