Python中的Decorator: 两种使用场景

使用 Python 中的Decorator完成以下功能, 代码均是在Python 3.6下编写:

  1. 记录函数调用时参数的 Log 工具
  2. 函数调用计数器.

分别使用 函数装饰器类装饰器 完成.

log 工具

创建一个 函数装饰器, 该装饰器的作用是输出其所wrap函数的函数名与参数, 很多时候可以作为日志工具, 追踪代码执行轨迹.

创建函数装饰器

    def log_func(func):
        def _wrapper(*args, **kwargs):
            print('Execute {} with args: {}, {}'.format(func.__name__, args, kwargs))
            return func(*args, **kwargs)
    return _wrapper

创建函数并使用装饰器

    @log_func
    def add(x, y, z):
        return x + y + z

在控制台调用函数, 检查控制台输出

    if __name__ == "__main__":
        a = add(2,3, z=5)
        print(a)

输出结果为

    Execute add() with args: (2, 3), {'z': 5}
    10

函数调用技术器

这是Python官方列出的装饰器的一种用法, 见页面PythonDecoratorLibrary#Counting_function_calls.

创建类装饰器, 该装饰器负责将wrap的函数, 存储在类的静态列表里, 并暴露两个静态方法, 用于显示单个函数或所有函数的调用次数统计情况.

创建类装饰器

    class countcalls(object):
       "Decorator that keeps track of the number of times a function is called."
       __instances = {}
       
        def __init__(self, f):
            self.__f = f
            self.__numcalls = 0
            countcalls.__instances[f] = self

       def __call__(self, *args, **kwargs):
          self.__numcalls += 1
          return self.__f(*args, **kwargs)

       @staticmethod
       def count(f):
          "Return the number of times the function f was called."
          return countcalls.__instances[f].__numcalls

       @staticmethod
       def counts():
          "Return a dict of {function: # of calls} for all registered functions."
          return dict([(f, countcalls.count(f)) for f in countcalls.__instances])

装饰器类countcalls, 拥有一个class level 变量 __instances = {}, 相当于是Java里的静态变量. 该变量用于存储所有函数的调用次数统计, key为函数对象, value为该函数对象所初始化出的countcalls的实例.

countcalls类的实例拥有一个实例变量 self.__numcalls, 并且会在装饰器被调用的时候更新数值. 即在 __call__()函数中更新.

创建函数并使用类装饰器countcalls

    @countcalls
    def add(x, y):
        return x + y

    @countcalls
    def sub(x, y):
        return x - y

调用函数, 并通过countcalls的静态方法查看调用统计

    if __name__ == "__main__":
        print(add(2, 3))
        print(add(10,23))
        print(sub(5, 6))

        counts = countcalls.counts()
        print(counts)

输出结果

    5
    33
    -1
    {: 2, : 1}

你可能感兴趣的:(Python中的Decorator: 两种使用场景)