python杂记

装饰器简介与使用

2016-10-29  本文已影响32人  摸不去的尘

装饰,《辞源》解释为“装者,藏也,饰者,物既成加以文采也。”指的是对器物表面添加纹饰、色彩以达到美化的目的。

python里的装饰器本质是一个函数,一个可以接受函数作为参数,返回值是函数的函数。它可以不改变一个函数代码的情况为这个函数提供额外功能,从而起到美化和重用代码作用。主要在用户验证、,插入日志、事物处理、缓存场景中使用。

例如,现在有两个函数代码如下:

def foo():
    ''' This is foo function '''
    print 'I am foo'
def bar():
    ''' This is bar function '''
    print 'I am bar'

现在需求有变更,需要给foo、bar两个函数添加日志来记录函数名字,防止以后出现问题便于定位问题:

def foo():
    ''' This is foo function '''
    logging.warn('foo is running' )
    print 'I am foo'

def bar():
    ''' This is bar function '''
    logging.warn('bar is running')
    print 'I am bar'

看可以上面那段代码出现了两次loggin.warn调用,每次需要改动原有函数代码,但是装饰器代码更简洁:

装饰器
def log(func):
    def wrapper(*args, **kwargs):
        logging.warn('%s is running % func.__name__)
        return func(*args, **kwargs)
    return wrapper

@log
def foo():
    ''' This is foo function '''
    print 'I am foo'

@log
def bar():
    ''' This is bar function '''
    print 'I am bar'

@是python一种语法糖,可以在被装饰函数上面用@加装饰器名,来使用装饰器。但是装饰器装饰函数,会创建一个动态函数来替换原来的,然而,新函数缺少会很多原函数的属性,如docstring和名字。幸好,万能的python提供functions包wraps函数来解决这个问题,修改后代码如下:

def log(func):
    @functions.wraps(func)     # 多了这行代码
    def wrapper(*args, **kwargs):
        logging.warn('%s is running % func.__name__)
        return func(*args, **kwargs)
    return wrapper

@log
def foo():
    ''' This is foo function '''
    print 'I am foo'

@log
def bar():
    ''' This is bar function '''
    print 'I am bar'

另外,如果传入被修饰函数带有位置参数和关键字参数,可以使用inspect.getcallargs提供更加智能处理方法,不用判断某个参数是位置参数还是关键字参数。只需要在inspect.callcargs返回参数名字-值为键值对的字典中查找即可,代码如下:

def log(func):
    @functions.wraps(func)
    def wrapper(*args,**kwargs):
        func_args = inspect.getcallargs(func, *args, **kwargs)   # 使用inspect内省功能获取参数
        if func_args.get('username') != 'admin':
           raise Exception('This user can not modify data')
        return func(*args, **kwargs)
    return wrapper
上一篇 下一篇

猜你喜欢

热点阅读