1. 程式人生 > >chapter5.2裝飾器

chapter5.2裝飾器

code 應該 ons update 一個 addition upd 信息 ota

裝飾器

有一個需求,將一個加法函數,增加一個功能,輸出調用的參數,及調用信息

在源代碼裏插入代碼,叫硬編碼,不利於更改。非業務功能輸出信息,不應該放在業務代碼裏。

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

def logger(fn,*args,**kwargs):
    print(sdfasd)
    ret = fn(*args,**kwargs)
    return ret
print(logger(add,4,5))

定義兩個函數,調用後加強輸出,但是函數傳參是個問題,使用以上方法,*args和**kwargs

將函數柯裏化

def logger(fn):
    def wn(*args,**kwargs):
        print(Function is {}.format(wn.__name__))
        wee = fn(*args,**kwargs)
        return wee
    return wn
def add(x,y):
  """ function add """
  return x+yprint(logger(add,4,5))

裝飾器語法糖

def logger(fn):
    def wn(*args,**kwargs):
        
print(Function is {}.format(fn.__name__)) wee = fn(*args,**kwargs) return wee return wn @logger ##==>add = logger(add) def add(x,y): """ function add """ return x+y ret = add(4,4) print(ret)

裝飾器(無參)

是一個函數,函數作為形參,返回值也是函數,可以使用@Functionname方式調用

以上總結不準確,只是方便理解

裝飾器就是高階函數,但裝飾器是對傳入函數的功能的增強(裝飾)

add = logger(add)

這句中函數被重新覆蓋,但是原來的add指向的地址被logger中的fn引用,仍然存在。這裏fn使用了閉包

def logger(fn):
    def wrap(*args,**kwargs):
        ‘‘‘This is a warp‘‘‘
        #
        print(function is {}.format(fn.__name__))
        print(doc: {}.format(fn.__doc__)) 
        
        ret = fn(*args,**kwargs)
        #
        return ret
    return wrap

@logger
def add(x,y):
    ‘‘‘This is a function of addition‘‘‘
    return x+y
ret = add(4,5)
print(ret,add.__doc__)

這裏可以調用fn.__doc__查看文檔屬性,想要看原來add的文件屬性,在全局只能看到logger的,python中提供有相應的函數,要是自己實現,可以使用兩層裝飾器。外層可以使用帶參函數

帶參裝飾器

def copy(src):
    def copy_inner (dst):
        dst.__name__ = src.__name__
        dst.__doc__ = src.__doc__
        return dst
    return copy_inner

def logger(fn):
    @copy(fn)####wrap = copy(fn)(wrap)
    def wrap(*args,**kwargs):
        ‘‘‘This is a warp‘‘‘
        #
        print(function is {}.format(fn.__name__))
        print(doc: {}.format(fn.__doc__)) 
        
        ret = fn(*args,**kwargs)
        #
        return ret
    return wrap

@logger###add = logger(add)
def add(x,y):
    ‘‘‘This is a function of addition‘‘‘
    return x+y
ret = add(4,5)
print(ret,add.__doc__)

以上函數,copy函數修飾了logger,將函數add的屬性復制到了函數warp上,只復制了名字和文檔的屬性

要想全部覆蓋,可以使用wrapper函數

from functools import wraps  functools類下的wraps方法

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

  類似於copy_properties功能

  wrapper包裝函數,被更新者,wrapper被包裝函數,數據源

  元組WRAPPER__ASSIGNMENTS中是要覆蓋的屬性

    (‘__module__‘, ‘__name__‘, ‘__qualname__‘, ‘__doc__‘, ‘__annotations__‘)

    模塊名,名稱,限定名,文檔,參數註解

  元組WRAPPER_UPDATES中是要被更新的屬性,__dict__屬性字典

  增加一個__wrapper__屬性,保留wrapped的屬性

import functools 

def logger(fn):
    def wrap(*args,**kwargs):
        ‘‘‘This is a warp‘‘‘
        
        print(function is {}.format(fn.__name__))
        print(doc: {}.format(fn.__doc__)) 
        
        ret = fn(*args,**kwargs)
        
        return ret
    return functools.update_wrapper(wrap,fn)

@logger###add = logger(add)
def add(x,y):
    ‘‘‘This is a function of addition‘‘‘
    return x+y
ret = add(4,5)
print(ret,add.__doc__)

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

wrapped 被包裝函數

import functools 

def logger(fn):
    @functools.wraps(fn)###==>wrap = wraps(fn)(wrap)
    def wrap(*args,**kwargs):
        ‘‘‘This is a warp‘‘‘
        
        print(function is {}.format(fn.__name__))
        print(doc: {}.format(fn.__doc__)) 
        
        ret = fn(*args,**kwargs)
        
        return ret
    return wrap

@logger###add = logger(add)
def add(x,y):
    ‘‘‘This is a function of addition‘‘‘
    return x+y
ret = add(4,5)
print(ret,add.__doc__)

chapter5.2裝飾器