python 装饰器

时间:2019-08-19 17:34:07   收藏:0   阅读:75

需求

def add1(x,y):
    print("call add, x+y") #日志输出的控制台
    return x+y

以上函数完成了需求,但是存在以下缺点:

业务功能分离

def add1(x,y):
    return x+y
def logger(fn):
    print("begin")
    x = fn(4,5)
    print("end")
    return x
print(logger(add1))

但这里fn调用传参是个问题

解决传参的问题

def add1(x,y):
    return x+y
def logger(fn,*args,**kwargs):
    print("begin")
    x = fn(*args,**kwargs) #这里是在解构
    print("end")
    return x
print(logger(add1,5,y=10))

柯里化

def add(x,y):
    return x+y
def logger(fn):
    def wrapper(*args,**kwargs):
        print("begin")
        x = fn(*args,**kwargs) #这里是在解构
        print("end")
        return x
    return wrapper


print(logger(add)(5,y = 10))

装饰器语法糖

def logger(fn):
    def wrapper(*args,**kwargs):
        print("begin")
        x = fn(*args,**kwargs) #这里是在解构
        print("end")
        return x
    return wrapper
@logger
def add(x,y):
    return x+y

print(add(45,500))

@logger是装饰器的语法

装饰器(无惨)

装饰器和高阶函数

import datetime
import time
def logger(fn):
    def wrapper(*args,**kwargs):
        print("begin")
        print("args={},kwargs={}".format(args,kwargs))
        start = datetime.datetime.now()
        x = fn(*args,**kwargs) #这里是在解构
        duration = datetime.datetime.now() -start
        print("function {} took {}s.".format(fn.__name__,duration.total_seconds()))
        return x
    return wrapper
@logger # add = logger(add)
def add(x,y):
    print("==========call add==========")
    time.sleep(2)
    return x+y

print(add(45,500))

Python 文档字符串

python文档

def add(x,y):
    """This is function of addition"""
    a = x+y
    return x+y
print("name={}\ndoc={}".format(add.__name__,add.__doc__))
print(help(add))

副作用出现的问题:

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

 原函数对象的属性都被替换了,而使用装饰器,我们的需求是查看被封装函数的属性,如何解决呢?

提供一个函数,被封装函数属性==copy==>包装函数属性

def copy_properties(src,dest): #可以改造成装饰器
    dest.__name__ = src.__name__
    dest.__doc__ = src.__doc__

def logger(fn):
    def wrapper(*args,**kwargs):
        "I am a wrapper"
        print("begin")
        x = fn(*args,**kwargs) #这里是在解构
        print("end")
        return x
    copy_properties(fn,wrapper)
    return wrapper
@logger #add= logger(add)
def add(x,y):
    "This is a function for add"
    return x+y
print("name={},doc={}".format(add.__name__,add.__doc__))

改造成带参装饰器

def copy_properties(src):#可以改造成装饰器
    def _copy_properties(dest):
        dest.__name__ = src.__name__
        dest.__doc__ = src.__doc__
        return dest
    return _copy_properties
def logger(fn):
    @copy_properties(fn) #wrapper = copy_properties(fn)(wrapper)
    def wrapper(*args,**kwargs):
        "I am a wrapper"
        print("begin")
        x = fn(*args,**kwargs) #这里是在解构
        print("end")
        return x
    return wrapper
@logger #add= logger(add)
def add(x,y):
    "This is a function for add"
    return x+y
print("name={},doc={}".format(add.__name__,add.__doc__))

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

import datetime
import time
def copy_properties(src):#可以改造成装饰器
    def _copy_properties(dest):
        dest.__name__ = src.__name__
        dest.__doc__ = src.__doc__
        return dest
    return _copy_properties
def loger(duration):
    def _logger(fn):
        @copy_properties(fn)
        def wrapper(*args,**kwargs):
            start = datetime.datetime.now()
            x = fn(*args, **kwargs)
            delta=(datetime.datetime.now()-start).total_seconds()
            print(so slow) if delta > duration else print(so fast)
            return x
        return wrapper
    return _logger
@loger(5)
def add(x,y):
    time.sleep(6)
    return x + y
print(add(10,24))

带参装饰器:

打印功能提出来

import datetime
import time
def copy_properties(src):#可以改造成装饰器 add
    def _copy_properties(dest): #wrapper
        dest.__name__ = src.__name__
        dest.__doc__ = src.__doc__
        return dest
    return _copy_properties
def loger(duration,func=lambda name,duration:print({} took {}s.format(name,duration))):  #loger(5)(add)  duration=5
    def _logger(fn):  #loger(5)(add) fn = add
        @copy_properties(fn) #wrapper = _copy_properties(fn)(wrapper)
        def wrapper(*args,**kwargs):
            start = datetime.datetime.now()
            x = fn(*args, **kwargs)
            delta=(datetime.datetime.now()-start).total_seconds()
            if delta > duration:
                func(fn.__name__,duration)
            return x
        return wrapper
    return _logger
@loger(5) #add = loger(5)(add)
def add(x,y):
    time.sleep(6)
    return x + y
print(add(10,24))

functools模块

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

import datetime, time, functools
def logger(duration, func=lambda name, duration: print({} took {}s.format(name, duration))):
    def _logger(fn):
        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 functools.update_wrapper(wrapper, fn)
    return _logger
@logger(5) # add = logger(5)(add)
def add(x,y):
    time.sleep(1)
    return x + y

print(add(5, 6), add.__name__, add.__wrapped__, add.__dict__, sep=\n)

@functools.wraps(wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)

import datetime, time, functools
def logger(duration, func=lambda name, duration: print({} took {}s.format(name, duration))):
    def _logger(fn):
        @functools.wraps(fn)
        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
@logger(5) # add = logger(5)(add)
def add(x,y):
    time.sleep(1)
    return x + y

print(add(5, 6), add.__name__, add.__wrapped__, add.__dict__, sep=\n)

 

原文:https://www.cnblogs.com/xzkzzz/p/11377065.html

评论(0
© 2014 bubuko.com 版权所有 - 联系我们:wmxa8@hotmail.com
打开技术之扣,分享程序人生!