python 装饰器二

昨天了解了python 装饰器的部分概念,今天继续昨天的内容稍作分析。首先还是来看一个装饰器

import time

def log(func):
    def wrapper(*args, **kw):
        print('func %s() is running' % func.__name__)
        return  func(*args, **kw)
    return wrapper

@log
def now():
    print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))

@符号是python 装饰器的语法糖。早期的写法是,定义好了装饰器后

now = log(now)

是将装饰器函数赋值给被装饰函数的同名变量。这种写法不太优雅,所以才在后续版本中加入了@语法糖的写法

带参数的装饰器

装饰器本质上是一个函数, python 是支持将函数本身赋值给变量的。 下面来看一个带参数的装饰器

import time

def log(level):
    def wrapper(func):
        def inner_wrapper(*args, **kwargs):
            print("[{level}]: enter function {func}".format(level=level, func=func.__name__)
            return func(*args, **kwargs)
        return inner_wrapper
    return wrapper

@log(level='INFO')
def now():
    print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))

这是一个带参数的装饰器,可以看到跟之前不带参数的装饰器相比,他多了一层结构,在wrapper 函数里面又定义了一层 inner_wrapper 方法。 这里的理解方式是: 当调用@log(level='INFO')时,可以将最外面一层看作是一个函数,函数返回的是一个装饰器。

functools

python 装饰器跟python 能够将函数对象赋值给变量的特性是密不可分的。当我们将 装饰器赋值给变量,然后打印 变量的函数名时,会出现装饰器内部的函数名。这时可以使用 functools

import functools

def log(text):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            print('%s %s():' % (text, func.__name__))
            return func(*args, **kw)
        return wrapper
    return decorator

在wrapper 定义之前 @function.wraps(func) 就可以避免上述的情况发生。

参考文档:
1、廖雪峰的python教程
2、 详解python装饰器

你可能感兴趣的:(python 装饰器二)