装饰器、带参装饰器、functools

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

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

增加信息输出功能:

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

缺点:

打印语句的耦合太高

加法函数属于业务功能,而输出信息属于非业务功能代码,不该放在业务中

 

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


def logger(fn):
    print('begin')  # 增加的输出
    x = fn(4, 5)
    print('end')  # 增加的功能
    return x


print(logger(add))

做到了业务功能分离,但是fn函数调用传参是个问题

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


def add2(x, y, z):
    return x + y + z


def add3(x, y, *args, z, **kwargs):
    return x + y + z


def logger(fn, *args, **kwargs):
    print('begin')
    a = fn(*args, **kwargs)
    print('end')
    return a


print(logger(add1, 5, y=61))
print(logger(add2, 5, 8, z=62))
print(logger(add3, 5, 7, z=63))
def add3(x, y, *args, z, **kwargs):
    return x + y + z


def logger(fn):    # 柯里化
    def looper(*args, **kwargs):   #  *可变参数
        print('begin')
        a = fn(*args, **kwargs)   #   *参数解构
        print('end')
        return a
    return looper


print(logger(add3)(5, 7, z=63))

装饰器: 

def logger(fn):    # 柯里化
    def _logger(*args, **kwargs):
        print('begin')
        a = fn(*args, **kwargs)
        print('end')
        return a
    return _logger


@logger    # add3 = logger(add3)
def add3(x, y, *args, z, **kwargs):
    return x + y + z


print(add3(4, 6, z=5))
import datetime
import time


def logger(fn):
    def wrap(*args, **kwargs):
        print("before")   # 调用前增强
        start = datetime.datetime.now()
        ret = fn(*args, **kwargs)
        print("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(4, 9))
import datetime
import time


def logger(fn):
    def wrap(*args, **kwargs):
        '''
        this a wrapper function
        :param args:
        :param kwargs:
        :return:
        '''
        print("before")   # 调用前增强
        start = datetime.datetime.now()
        ret = fn(*args, **kwargs)
        print("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):
    '''
    this is a add function
    :param x:
    :param y:
    :return:
    '''
    print("----call add----")
    time.sleep(2)
    return x + y


print(add(4, 9), add.__doc__, add.__name__, sep='\n')

# 这样输出的文档是wrap的,名字也是wrap的,需求是业务函数的信息
import datetime
import time


def copy_properties(src, dst):   # 可以改为装饰器
    dst.__doc__ = src.__doc__
    dst.__name__ = src.__name__


def logger(fn):
    def wrap(*args, **kwargs):
        '''
        this a wrapper function
        :param args:
        :param kwargs:
        :return:
        '''
        print("before")   # 调用前增强
        start = datetime.datetime.now()
        ret = fn(*args, **kwargs)
        print("after")   # 调用后增强
        duration = datetime.datetime.now() - start
        print("function {} took {}s".format(fn.__name__, duration.total_seconds()))
        return ret
    copy_properties(fn, wrap)
    return wrap


@logger
def add(x, y):
    '''
    this is a add function
    :param x:
    :param y:
    :return:
    '''
    print("----call add----")
    time.sleep(2)
    return x + y


print(add(4, 9), add.__doc__, add.__name__, sep='\n')


out:
before
----call add----
after
function add took 2.000802s
13

    this is a add function
    :param x:
    :param y:
    :return:
    
add
#  这样就OK了
import datetime
import time


def copy_properties(src):    # 拷贝业务函数属性
    def _copy(dst):
        dst.__doc__ = src.__doc__
        dst.__name__ = src.__name__
        dst.__qualname__ = src.__qualname__
        return dst
    return _copy


def logger(fn):
    @copy_properties(fn)  # ---> copy_properties(add) --> @_copy --> wrap = _copy(wrap)
    def wrap(*args, **kwargs):
        '''
        this a wrapper function
        :param args:
        :param kwargs:
        :return:
        '''
        print("before")   # 调用前增强
        start = datetime.datetime.now()
        ret = fn(*args, **kwargs)
        print("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):
    '''
    this is a add function xxxxxxx
    :param x:
    :param y:
    :return:
    '''
    print("----call add----")
    time.sleep(2)
    return x + y


print(add(4, 9), add.__doc__, add.__name__, add.__qualname__, sep='\n')
import datetime
import time


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


def logger(t1, t2):
    def _logger(fn):
        @copy_properties(fn)
        def wrap(*args, **kwargs):
            '''
            this a wrapper function
            :param args:
            :param kwargs:
            :return:
            '''
            print("before")   # 调用前增强
            start = datetime.datetime.now()
            ret = fn(*args, **kwargs)
            print("after")   # 调用后增强
            duration = (datetime.datetime.now() - start).total_seconds()
            print("function {} took {}s".format(fn.__name__, duration)) if duration < t1 else print("so slow")
            # if t2 > duration > t1:
                # print(".....")
            return ret
        return wrap
    return _logger


@logger(3, 6)   # add = logger(3)(add) = _logger(add)   带参装饰器
def add(x, y):
    '''
    this is a add function xxxxxxx
    :param x:
    :param y:
    :return:
    '''
    print("----call add----")
    time.sleep(4)
    return x + y


print(add(4, 9), add.__doc__, add.__name__, add.__qualname__, sep='\n')
import datetime
import time
import functools


def logger(t1, t2):
    def _logger(fn):
       #@functools.wraps(fn)   # 可以直接用装饰器 functools.update_wrapper(wrap, fn)
        def wrap(*args, **kwargs):
            '''
            this a wrapper function
            :param args:
            :param kwargs:
            :return:
            '''
            print("before")   # 调用前增强
            start = datetime.datetime.now()
            ret = fn(*args, **kwargs)
            print("after")   # 调用后增强
            duration = (datetime.datetime.now() - start).total_seconds()
            print("function {} took {}s".format(fn.__name__, duration)) if duration < t1 else print("so slow")
            # if t2 > duration > t1:
                #  print(".....")
            return ret
        functools.update_wrapper(wrap, fn)       # 可被上面的注释行替代
        print("{} {}".format(id(wrap), id(fn)))  # id可以看到是装饰函数,还是被装饰的函数
        return wrap
    return _logger


@logger(3, 6)   # add = logger(3)(add) = _logger(add)
def add(x, y):
    '''
    this is a add function xxxxxxx
    :param x:
    :param y:
    :return:
    '''
    print("----call add----")
    time.sleep(4)
    return x + y


print(add(4, 9), add.__doc__, add.__name__, add.__qualname__, sep='\n')
print("############")
print(add.__wrapped__)
print(id(add.__wrapped__))


out:

2149881420792 2149881028952(被包装函数add)
before
----call add----
after
so slow
13

    this is a add function xxxxxxx
    :param x:
    :param y:
    :return:
    
add
add
############
<function add at 0x000001F48EE52158>
2149881028952 (被包装函数add,也就是说add.__wrapped__属性是add的)
import datetime
import time
import functools


def logger(t1, t2, func=lambda name, duration: print('{} took {}s'.format(name, duration))):
    def _logger(fn):
        @functools.wraps(fn)
        def wrap(*args, **kwargs):
            '''
            this a wrapper function
            :param args:
            :param kwargs:
            :return:
            '''
            print("before")   # 调用前增强
            start = datetime.datetime.now()
            ret = fn(*args, **kwargs)
            print("after")   # 调用后增强
            duration = (datetime.datetime.now() - start).total_seconds()
            func if duration < t1 else print("so slow")
            # if t2 > duration > t1:
            #     print(".....")
            return ret
        # functools.update_wrapper(wrap, fn)
        print("{} {}".format(id(wrap), id(fn)))
        return wrap
    return _logger


@logger(2, 6)   # add = logger(3)(add) = _logger(add)
def add(x, y):
    '''
    this is a add function xxxxxxx
    :param x:
    :param y:
    :return:
    '''
    print("----call add----")
    time.sleep(4)
    return x + y


print(add(4, 9), add.__doc__, add.__name__, add.__qualname__, sep='\n')
print("############")
print(add.__wrapped__)
print(id(add.__wrapped__))


这版OK

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章