一个通用的运行时间装饰器

2022-08-31 10:17:37 浏览数 (1)

这个装饰器只解决一个问题:“这个程序中这个函数运行需要多久?”

最近在用 Python3 写一个程序,功能已经实现了,但是运行速度太慢了,慢到令人发指,为了让这个程序的存在具有意义,我需要把这些功能函数耗费的时间大概了解,找出那些运行时间比较长的,之后有针对性地解决

所以,获取程序中各函数运行时间成了当务之急,这里涉及两个小困难:

  • 函数众多,在每个函数中都加上计算时间的代码会很繁琐,最后还得删除 这个解决起来不难,用装饰器就可以解决,不需要修改代码
  • 函数绝大多数都定义在类中,这样普通的运行时间装饰器就会产生不兼容的情况 所以就有了下面这个通用装饰器
代码语言:javascript复制
import datetime
import wrapt
import inspect


# 通用时间装饰器
@wrapt.decorator
def universal(wrapped, instance, args, kwargs):
    if instance is None:
        if inspect.isclass(wrapped):
            # 装饰一个类
            # Decorator was applied to a class.
            return wrapped(*args, **kwargs)
        else:
           # 装饰一个普通函数或者静态方法
            # Decorator was applied to a function or staticmethod.
            ret = consume_time(wrapped=wrapped, args=args, kwargs=kwargs)
            return ret
    else:
        if inspect.isclass(instance):
            # 装饰类方法
            # Decorator was applied to a classmethod.
            ret = consume_time(wrapped=wrapped, args=args, kwargs=kwargs)
            return ret
        else:
           # 装饰实例方法
            ret = consume_time(wrapped=wrapped, args=args, kwargs=kwargs)
            return ret
           
def consume_time(wrapped, args, kwargs):
    local_time = datetime.datetime.now()
    ret = wrapped(*args, **kwargs)
    times = (datetime.datetime.now() - local_time).seconds
    funcname = wrapped.__name__
    print('运行 {} 函数消耗的时间为 {} 分 {} 秒'.format(
        funcname, times // 60, times % 60))
    # print('Run {} time is {} minutes {} seconds'.format(
    #     funcname, times // 60, times % 60))
    return ret

既然说是通用装饰器,怎么个通用法呢?它可以作用于以下内容

  • 普通函数
  • 类静态方法
  • 类方法
  • 实例方法

接下来我们测试一下

【未加装饰器的程序】

代码语言:javascript复制
import time


class People:
    # 定义基本属性
    name = ""
    age = 0

    # 初始化函数
    def __init__(self, name, age):
        self.name = name
        self.age = age 
    
    # 静态方法
    @staticmethod
    def work():
        time.sleep(3)
        print("I could work")

    # 类方法
    @classmethod
    def speak(cls, words):
        time.sleep(1)
        print(words)

    # 实例方法
    def eat(self, food):
        time.sleep(5)
        print(f"I am eating {food}")
    
# 普通函数
def read(bookname):
    time.sleep(1)
    print(f"I am reading {bookname}")


# 调用普通函数
read("《Linux 二进制分析》")

# 调用静态方法
People.work()

# 调用类方法
People.speak("hello world")

## 调用实例方法
# 实例化一个对象
xiaoming = People(name="xiaoming", age=18)
xiaoming.eat("a sandwich")

运行后结果

现在我们加上时间装饰器,来看看这些函数都消耗了多少时间

【已经加上装饰器的程序】

为了演示装饰不同内容,我们给装饰器每个分支都加上 print

代码语言:javascript复制
import datetime
import time
import wrapt
import inspect


@wrapt.decorator
def universal(wrapped, instance, args, kwargs):
    funcname = wrapped.__name__
    if instance is None:
        if inspect.isclass(wrapped):
            print("-" * 50)
            print("正在装饰一个类")
            return wrapped(*args, **kwargs)
        else:
            print("-" * 50)
            print(f"正在装饰一个普通函数或者静态方法: {funcname}")
            ret = consume_time(wrapped=wrapped, args=args, kwargs=kwargs)
            return ret
    else:
        if inspect.isclass(instance):
            print("-" * 50)
            print(f"正在装饰类方法: {funcname}")
            ret = consume_time(wrapped=wrapped, args=args, kwargs=kwargs)
            return ret
        else:
            print("-" * 50)
            print(f"正在装饰实例方法: {funcname}")
            ret = consume_time(wrapped=wrapped, args=args, kwargs=kwargs)
            print("-" * 50)
            return ret

def consume_time(wrapped, args, kwargs):
    local_time = datetime.datetime.now()
    ret = wrapped(*args, **kwargs)
    times = (datetime.datetime.now() - local_time).seconds
    funcname = wrapped.__name__
    print('运行 {} 函数消耗的时间为 {} 分 {} 秒'.format(
        funcname, times // 60, times % 60))
    # print('Run {} time is {} minutes {} seconds'.format(
    #     funcname, times // 60, times % 60))
    return ret

@universal
class People:
    # 定义基本属性
    name = ""
    age = 0

    # 初始化函数
    def __init__(self, name, age):
        self.name = name
        self.age = age 
    
    # 静态方法
    @universal
    @staticmethod
    def work():
        time.sleep(3)
        print("I could work")

    # 类方法
    @universal
    @classmethod
    def speak(cls, words):
        time.sleep(1)
        print(words)

    # 实例方法
    @universal
    def eat(self, food):
        time.sleep(5)
        print(f"I am eating {food}")
    
# 普通函数
@universal
def read(bookname):
    time.sleep(1)
    print(f"I am reading {bookname}")


# 调用普通函数
read("《Linux 二进制分析》")

# 调用静态方法
People.work()

# 调用类方法
People.speak("hello world")

## 调用实例方法
# 实例化一个对象
xiaoming = People(name="xiaoming", age=18)
xiaoming.eat("a sandwich")

运行后结果

我们可以直观地看到, eat 这个函数运行时间最长,运行时间为 5 秒,可能需要我们针对性解决

如果你不想复制装饰器文件,可以直接从以下百度云链接中下载

https://pan.baidu.com/s/1mO9W2QGeJRp8qNjWzelUvw 提取码: ajp4

0 人点赞