chapter5.2装饰器

装饰器

有一个需求,将一个加法函数,增加一个功能,输出调用的参数,及调用信息

在源代码里插入代码,叫硬编码,不利于更改。非业务功能输出信息,不应该放在业务代码里。

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方式调用

以上总结不准确,只是方便理解

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

扫描二维码关注公众号,回复: 2949763 查看本文章

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__)

猜你喜欢

转载自www.cnblogs.com/rprp789/p/9545459.html
5.2