裝飾器、帶參裝飾器、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

 

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