Python3 装饰器理解

2022-09-05 13:57:30 浏览数 (1)

Contents

  • 1 装饰器介绍
    • 1.1 @语法糖
    • 1.2 args、*kwargs,可变参数与关键字参数
    • 1.3 带参数的装饰器
  • 2 装饰器示例
  • 3 总结
  • 4 参考资料

在代码运行期间给函数动态增加功能的方式,称之为“装饰器”( Decorator),装饰器的本质是一个返回函数的高阶函数。

装饰器介绍

谈装饰器之前,需明白一件事,Python 中的函数和 Java、C 不一样,Python 中的函数可以像普通变量一样当做参数传递给另外一个函数,代码示例如下:

代码语言:javascript复制
def foo():
    print('hello world')
def decorator(function):
    function()
decorator(foo)

装饰器本质上是一个能返回函数的高阶函数它可以让其他函数或类在不需要做任何代码修改的前提下增加额外功能,装饰器的返回值也是一个函数/类对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景,装饰器是解决这类问题的绝佳设计。有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码到装饰器中并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。 简单装饰器示例代码如下:

代码语言:javascript复制
import logging
def use_logging(func):
    def wrapper():
        logging.warn("%s is running" % func.__name__)
        return func()
    return wrapper
def foo():
    print('I am foo')
foo = use_logging(foo) # 因为装饰器 use_logging(foo) 返回的是函数对象 wrapper,这条语句相当于 foo = wrapper
foo()

程序输出如下:

WARNING:root:foo is running  I am foo

@语法糖

Python 内置的 @property 装饰器是负责把一个方法变成属性调用的,有了 @,就可以省去foo = use_logging(foo)这一句,直接调用 foo() 即可实现相同的功能。

代码语言:javascript复制
def use_logging(func):
    def wrapper():
        logging.warn("%s is running" % func.__name__)
        return func()
    return wrapper
@use_logging
def foo():
    print("i am foo")
foo()

有了 Python 的 @ 语法,把 decorator 置于函数 foo 定义处,调用 foo 函数,相当于执行语句 foo = use_logging(foo)

args、*kwargs,可变参数与关键字参数

可以在定义 wrapper 函数的时候指定参数,参数可以是可变参数 *args、关键字参数**kwargs。

可变参数允许你传入 0 个或任意个参数,这些可变参数在函数调用时自动组装为一个 tuple。而关键字参数允许你传入 0 个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个 dict

给 wrapper 函数添加参数的示例代码如下:

代码语言:javascript复制
def wrapper(*args, **kwargs):
        # args是一个数组,kwargs一个字典
        logging.warn("%s is running" % func.__name__)
        return func(*args, **kwargs)
    return wrapper

带参数的装饰器

装饰器还有更大的灵活性,例如带参数的装饰器,在上面的装饰器调用中,该装饰器接收唯一的参数就是执行业务的函数 foo 。装饰器的语法允许我们在调用时,提供其它参数,比如 @decorator(a)。示例代码如下:

代码语言:javascript复制
def use_logging(level):
    def decorator(func):
        def wrapper(*args, **kwargs):
            if level == "warn":
                logging.warn("%s is running" % func.__name__)
            elif level == "info":
                logging.info("%s is running" % func.__name__)
            return func(*args)
        return wrapper
    return decorator
@use_logging(level="info")
def foo(name='foo'):
    print("i am %s" % name)
foo()

程序输出如下:

i am foo

装饰器示例

可打印函数运行时间的装饰器,代码如下:

代码语言:javascript复制
# decorator: print the cost time of run function
def runTime(func):
   def wapper(arg, *args, **kwargs):
      print("function name: %s" %func.__name__)
      start = time.time()
      res = func(arg, *args, **kwargs)
      end = time.time()
      print("run time: %.2fs" %(end - start))
      print("="*30)
      return res
   return wapper

总结

实现装饰器知识储备:  a、函数即“变量”  b、高阶函数  c、函数嵌套  d、高阶函数 嵌套函数==》装饰器  在面向对象( OOP)的设计模式中, decorator 被称为装饰模式。 OOP 的装饰模式需要通过继承和组合来实现,而 Python 除了能支持 OOP 的decorator外,直接从语法层次支持 decorator。Python 的 decorator 可以用函数实现,也可以用类实现。

参考资料

理解Python装饰器看这一篇就够了

0 人点赞