Python中的装饰器有很多用处,比如输出日志、参数检查、代理设置、计数计时、结果缓存等等。本文就通过几个装饰器例子,详细解释一下Python中装饰器的用法。

  • 一步步从简到繁学习装饰器用法
  • 其他一些装饰器实例
  • Python中自带的装饰器


按照惯例,先上代码:GitHub - xianhu/LearnPython: 以撸代码的形式学习Python

一步步从简到繁学习装饰器用法

(1)最简单的装饰器,实现日志输出功能:

# 构建装饰器
def logging(func):
    @functools.wraps(func)
    def decorator():
        print("%s called" % func.__name__)
        result = func()
        print("%s end" % func.__name__)
        return result
    return decorator

# 使用装饰器
@logging
def test01():
    return 1

# 测试用例
print(test01())
print(test01.__name__)

代码很简单,很容易看懂。这里注意"functools.wraps"用法,其目的是"test01.__name__"输出正确的"test01"。"@logging"相当于"test01 = logging(test01)",返回的是decorator函数,所以如果不加"functools.wraps",则"test01.__name__"返回为"decorator"。

注意,此时test01没有参数,对于带有参数的函数,logging装饰器则不再适用。那么如果想装饰带有参数的函数,装饰器该怎么写呢?

(2)装饰器传入函数参数,并正确返回结果:

# 构建装饰器
def logging(func):
    @functools.wraps(func)
    def decorator(a, b):
        print("%s called" % func.__name__)
        result = func(a, b)
        print("%s end" % func.__name__)
        return result
    return decorator

# 使用装饰器
@logging
def test01(a, b):
    print("in function test01, a=%s, b=%s" % (a, b))
    return 1

# 测试用例
print(test01(1, 2))

这里的test01函数带有参数a、b,那么decorator函数带有同样的参数即可。那么问题又来了,如何让logging装饰器更加通用,而不是只装饰参数为两个的函数呢?这时候自然想到Python中的 * 和 ** 的用法。

# 构建装饰器
def logging(func):
    @functools.wraps(func)
    def decorator(*args, **kwargs):
        print("%s called" % func.__name__)
        result = func(*args, **kwargs)
        print("%s end" % func.__name__)
        return result
    return decorator

# 使用装饰器
@logging
def test01(a, b):
    print("in function test01, a=%s, b=%s" % (a, b))
    return 1

# 使用装饰器
@logging
def test02(a, b, c=1):
    print("in function test02, a=%s, b=%s, c=%s" % (a, b, c))
    return 1

# 测试用例
print(test01(1, 2))
print(test02(1, 2, c=3, d

相关文章: