这个装饰器只解决一个问题:“这个程序中这个函数运行需要多久?”
最近在用 Python3 写一个程序,功能已经实现了,但是运行速度太慢了,慢到令人发指,为了让这个程序的存在具有意义,我需要把这些功能函数耗费的时间大概了解,找出那些运行时间比较长的,之后有针对性地解决
所以,获取程序中各函数运行时间成了当务之急,这里涉及两个小困难:
- 函数众多,在每个函数中都加上计算时间的代码会很繁琐,最后还得删除 这个解决起来不难,用装饰器就可以解决,不需要修改代码
- 函数绝大多数都定义在类中,这样普通的运行时间装饰器就会产生不兼容的情况 所以就有了下面这个通用装饰器
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
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