我的编程空间,编程开发者的网络收藏夹
学习永远不晚

如何用装饰器扩展Python计时器

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

如何用装饰器扩展Python计时器

这篇文章主要介绍“如何用装饰器扩展Python计时器”,在日常操作中,相信很多人在如何用装饰器扩展Python计时器问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何用装饰器扩展Python计时器”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

1. 每次调用函数时使用 Timer:
with Timer("some_name"):do_something()

当我们在一个py文件里多次调用函数 do_something(),那么这将会变得非常繁琐并且难以维护。

2. 将代码包装在上下文管理器中的函数中:
def do_something():with Timer("some_name"):...

Timer 只需要在一个地方添加,但这会为do_something()的整个定义增加一个缩进级别。

更好的解决方案是使用 Timer 作为装饰器。装饰器是用于修改函数和类行为的强大构造。

理解 Python 中的装饰器

装饰器是包装另一个函数以修改其行为的函数。你可能会有疑问,这怎么实现呢?其实函数是 Python 中的first-class 对象,换句话说,函数可以以变量的形式传递给其他函数的参数,就像任何其他常规对象一样。因此此处有较大的灵活性,也是 Python 几个最强大功能的基础。

我们首先创建第一个示例,一个什么都不做的装饰器:

def turn_off(func):return lambda *args, **kwargs: None

首先注意这个turn_off()只是一个常规函数。之所以成为装饰器,是因为它将一个函数作为其唯一参数并返回另一个函数。我们可以使用turn_off()来修改其他函数,例如:

>>> print("Hello")Hello>>> print = turn_off(print)>>> print("Hush")>>> # Nothing is printed

代码行 print = turn_off(print) 用 turn_off() 装饰器装饰了 print 语句。实际上,它将函数 print() 替换为匿名函数 lambda *args, **kwargs: None 并返回 turn_off()。匿名函数 lambda 除了返回 None 之外什么都不做。

要定义更多丰富的装饰器,需要了解内部函数。内部函数是在另一个函数内部定义的函数,它的一种常见用途是创建函数工厂:

def create_multiplier(factor):def multiplier(num):return factor * numreturn multiplier

multiplier() 是一个内部函数,在 create_multiplier() 内部定义。注意可以访问 multiplier() 内部的因子,而 multiplier()未在 create_multiplier() 外部定义:

multiplier
Traceback (most recent call last):File "", line 1, inNameError: name 'multiplier' is not defined

相反,可以使用create_multiplier()创建新的 multiplier 函数,每个函数都基于不同的参数factor:

double = create_multiplier(factor=2)double(3)
6
quadruple = create_multiplier(factor=4)quadruple(7)
28

同样,可以使用内部函数来创建装饰器。装饰器是一个返回函数的函数:

def triple(func):def wrapper_triple(*args, **kwargs):print(f"Tripled {func.__name__!r}")value = func(*args, **kwargs)return value * 3return wrapper_triple

triple() 是一个装饰器,因为它是一个期望函数 func() 作为其唯一参数并返回另一个函数 wrapper_triple() 的函数。注意 triple() 本身的结构:

  • 第 1 行开始了triple() 的定义,并期望一个函数作为参数。

  • 第 2 到 5 行定义了内部函数wrapper_triple()。

  • 第 6 行返回wrapper_triple()。

这是种定义装饰器的一般模式(注意内部函数的部分):

  • 第 2 行开始wrapper_triple() 的定义。此函数将替换triple() 修饰的任何函数。参数是*args 和**kwargs,用于收集传递给函数的任何位置参数和关键字参数。我们可以灵活地在任何函数上使用triple()。

  • 第 3 行打印出修饰函数的名称,并指出已对其应用了triple()。

  • 第 4 行调用func(),triple() 修饰的函数。它传递传递给wrapper_triple() 的所有参数。

  • 第 5 行将func() 的返回值增加三倍并将其返回。

接下来的代码中,knock() 是一个返回单词 Penny 的函数,将其传给triple() 函数,并看看输出结果是什么。

>>> def knock():... return "Penny! ">>> knock = triple(knock)>>> result = knock()Tripled 'knock'>>> result'Penny! Penny! Penny! '

我们都知道,文本字符串与数字相乘,是字符串的一种重复形式,因此字符串 'Penny' 重复了 3 次。可以认为,装饰发生在knock = triple(knock)。

上述方法虽然实现了装饰器的功能,但似乎有点笨拙。PEP 318 引入了一种更方便的语法来应用装饰器。下面的 knock() 定义与上面的定义相同,但装饰器用法不同。

>>> @triple... def knock():... return "Penny! "...>>> result = knock()Tripled 'knock'>>> result'Penny! Penny! Penny! '

@ 符号用于应用装饰器,@triple 表示 triple() 应用于紧随其后定义的函数。

Python 标准库中定义的装饰器方法之一是:@functools.wraps。这在定义你自己的装饰器时非常有用。前面说过,装饰器是用另一个函数替换了一个函数,会给你的函数带来一个微妙的变化:

knock
<function triple..wrapper_triple at 0x7fa3bfe5dd90>

@triple 装饰了 knock(),然后被 wrapper_triple() 内部函数替换,被装饰的函数的名字会变成装饰器函数,除了名称,还有文档字符串和其他元数据都将会被替换。但有时,我们并不总是想将被修饰的函数的所有信息都被修改了。此时 @functools.wraps 正好解决了这个问题,如下所示:

import functoolsdef triple(func):@functools.wraps(func)def wrapper_triple(*args, **kwargs):print(f"Tripled {func.__name__!r}")value = func(*args, **kwargs)return value * 3return wrapper_triple

使用 @triple 的这个新定义保留元数据:

@tripledef knock():return "Penny! "knock

注意knock() 即使在被装饰之后,也同样保留了它的原有函数名称。当定义装饰器时,使用 @functools.wraps 是一种不错的选择,可以为大多数装饰器使用的如下模板:

import functoolsdef decorator(func):@functools.wraps(func)def wrapper_decorator(*args, **kwargs):# Do something beforevalue = func(*args, **kwargs)# Do something afterreturn valuereturn wrapper_decorator

创建 Python 定时器装饰器

在本节中,云朵君将和大家一起学习如何扩展 Python 计时器,并以装饰器的形式使用它。接下来我们从头开始创建 Python 计时器装饰器。

根据上面的模板,我们只需要决定在调用装饰函数之前和之后要做什么。这与进入和退出上下文管理器时的注意事项类似。在调用修饰函数之前启动 Python 计时器,并在调用完成后停止 Python 计时器。可以按如下方式定义 @timer 装饰器:

import functoolsimport timedef timer(func):@functools.wraps(func)def wrapper_timer(*args, **kwargs):tic = time.perf_counter()value = func(*args, **kwargs)toc = time.perf_counter()elapsed_time = toc - ticprint(f"Elapsed time: {elapsed_time:0.4f} seconds")return valuereturn wrapper_timer

可以按如下方式应用 @timer:

@timerdef download_data():source_url = 'https://cloud.tsinghua.edu.cn/d/e1ccfff39ad541908bae/files/?p=%2Fall_six_datasets.zip&dl=1'headers = {'User-Agent': 'Mozilla/5.0'}res = requests.get(source_url, headers=headers) download_data()# Python Timer Functions: Three Ways to Monitor Your Code
[ ... ]Elapsed time: 0.5414 seconds

回想一下,还可以将装饰器应用于先前定义的下载数据的函数:

requests.get = requests.get(source_url, headers=headers)

使用装饰器的一个优点是只需要应用一次,并且每次都会对函数计时:

data = requests.get(0)
Elapsed time: 0.5512 seconds

虽然@timer 顺利完成了对目标函数的定时。但从某种意义上说,你又回到了原点,因为该装饰器 @timer 失去了前面定义的类 Timer 的灵活性或便利性。换句话说,我们需要将 Timer 类表现得像一个装饰器。

现在我们似乎已经将装饰器用作应用于其他函数的函数,但其实不然,因为装饰器必须是可调用的。Python中有许多可调用的类型,可以通过在其类中定义特殊的.__call__()方法来使自己的对象可调用。以下函数和类的行为类似:

def square(num):return num ** 2square(4)
16
class Squarer:def __call__(self, num):return num ** 2square = Squarer()square(4)
16

这里,square 是一个可调用的实例,可以对数字求平方,就像square()第一个示例中的函数一样。

我们现在向现有Timer类添加装饰器功能,首先需要 import functools。

# timer.pyimport functools# ...@dataclassclass Timer:# The rest of the code is unchangeddef __call__(self, func):"""Support using Timer as a decorator"""@functools.wraps(func)def wrapper_timer(*args, **kwargs):with self:return func(*args, **kwargs)return wrapper_timer

在之前定义的上下文管理器 Timer ,给我们带来了不少便利。而这里使用的装饰器,似乎更加方便。

@Timer(text="Downloaded the tutorial in {:.2f} seconds")def download_data():source_url = 'https://cloud.tsinghua.edu.cn/d/e1ccfff39ad541908bae/files/?p=%2Fall_six_datasets.zip&dl=1'headers = {'User-Agent': 'Mozilla/5.0'}res = requests.get(source_url, headers=headers) download_data()# Python Timer Functions: Three Ways to Monitor Your Code
[ ... ]Downloaded the tutorial in 0.72 seconds

有一种更直接的方法可以将 Python 计时器变成装饰器。其实上下文管理器和装饰器之间的一些相似之处:它们通常都用于在执行某些给定代码之前和之后执行某些操作。

基于这些相似之处,在 python 标准库中定义了一个名为 ContextDecorator 的 mixin 类,它可以简单地通过继承 ContextDecorator 来为上下文管理器类添加装饰器函数。

from contextlib import ContextDecorator# ...@dataclassclass Timer(ContextDecorator):# Implementation of Timer is unchanged

当以这种方式使用 ContextDecorator 时,无需自己实现 .__call__(),因此我们可以大胆地将其从 Timer 类中删除。

使用 Python 定时器装饰器

接下来,再最后一次重改 download_data.py 示例,使用 Python 计时器作为装饰器:

# download_data.pyimport requestsfrom timer import Timer@Timer()def main():source_url = 'https://cloud.tsinghua.edu.cn/d/e1ccfff39ad541908bae/files/?p=%2Fall_six_datasets.zip&dl=1'headers = {'User-Agent': 'Mozilla/5.0'}res = requests.get(source_url, headers=headers) with open('dataset/datasets.zip', 'wb') as f:f.write(res.content)if __name__ == "__main__":main()

我们与之前的写法进行比较,唯一的区别是第 3 行的 Timer 的导入和第 4 行的 @Timer()  的应用。使用装饰器的一个显着优势是它们通常很容易调用。

但是,装饰器仍然适用于整个函数。这意味着代码除了记录了下载数据所需的时间外,还考虑了保存数据所需的时间。运行脚本:

$ python download_data.py# Python Timer Functions: Three Ways to Monitor Your Code
[ ... ]Elapsed time: 0.69 seconds

从上面打印出来的结果可以看到,代码记录了下载数据和保持数据一共所需的时间。

当使用 Timer 作为装饰器时,会看到与使用上下文管理器类似的优势:

  • 省时省力:只需要一行额外的代码即可为函数的执行计时。

  • 可读性:当添加装饰器时,可以更清楚地注意到代码会对函数计时。

  • 一致性:只需要在定义函数时添加装饰器即可。每次调用时,代码都会始终如一地计时。

然而,装饰器不如上下文管理器灵活,只能将它们应用于完整函数。

Python 计时器代码

这里展开下面的代码块以查看 Python 计时器timer.py的完整源代码。

上下滑动查看更多源码
# timer.pyimport timefrom contextlib import ContextDecoratorfrom dataclasses import dataclass, fieldfrom typing import Any, Callable, ClassVar, Dict, Optionalclass TimerError(Exception):"""A custom exception used to report errors in use of Timer class"""@dataclassclass Timer(ContextDecorator):"""Time your code using a class, context manager, or decorator"""timers: ClassVar[Dict[str, float]] = {}name: Optional[str] = Nonetext: str = "Elapsed time: {:0.4f} seconds"logger: Optional[Callable[[str], None]] = print_start_time: Optional[float] = field(default=None, init=False, repr=False)def __post_init__(self) -> None:"""Initialization: add timer to dict of timers"""if self.name:self.timers.setdefault(self.name, 0)def start(self) -> None:"""Start a new timer"""if self._start_time is not None:raise TimerError(f"Timer is running. Use .stop() to stop it")self._start_time = time.perf_counter()def stop(self) -> float:"""Stop the timer, and report the elapsed time"""if self._start_time is None:raise TimerError(f"Timer is not running. Use .start() to start it")# Calculate elapsed timeelapsed_time = time.perf_counter() - self._start_timeself._start_time = None# Report elapsed timeif self.logger:self.logger(self.text.format(elapsed_time))if self.name:self.timers[self.name] += elapsed_timereturn elapsed_timedef __enter__(self) -> "Timer":"""Start a new timer as a context manager"""self.start()return selfdef __exit__(self, *exc_info: Any) -> None:"""Stop the context manager timer"""self.stop()

可以自己使用代码,方法是将其保存到一个名为的文件中timer.py并将其导入:

from timer import Timer

PyPI 上也提供了 Timer,因此更简单的选择是使用 pip 安装它:

pip install codetiming

注意,PyPI 上的包名称是codetiming,安装包和导入时都需要使用此名称Timer:

from codetiming import Timer

除了名称和一些附加功能之外,codetiming.Timer 与 timer.Timer 完全一样。总而言之,可以通过三种不同的方式使用 Timer:

作为一个类:

t = Timer(name="class")t.start()# Do somethingt.stop()

作为上下文管理器:

with Timer(name="context manager"):# Do something

作为装饰器:

@Timer(name="decorator")def stuff():# Do something

这种 Python 计时器主要用于监控代码在单个关键代码块或函数上所花费的时间。

Python定时器装饰器已经学习完毕了,接下来是总结了一些其他的 Python 定时器函数,如果你对其不太感兴趣,可以直接跳到最后。

其他 Python 定时器函数

使用 Python 对代码进行计时有很多选择。这里我们学习了如何创建一个灵活方便的类,可以通过多种不同的方式使用该类。对 PyPI 的快速搜索发现,已经有许多项目提供 Python 计时器解决方案。

在本节中,我们首先了解有关标准库中用于测量时间的不同函数的更多信息,包括为什么 perf_counter() 更好,然后探索优化代码的替代方案。

使用替代 Python 计时器函数

在本文之前,包括前面介绍python定时器的文章中,我们一直在使用 perf_counter() 来进行实际的时间测量,但是 Python 的时间库附带了几个其他也可以测量时间的函数。这里有一些:

  • time()

  • perf_counter_ns()

  • monotonic()

  • process_time()

拥有多个函数的一个原因是 Python 将时间表示为浮点数。浮点数本质上是不准确的。之前可能已经看到过这样的结果:

>>> 0.1 + 0.1 + 0.10.30000000000000004>>> 0.1 + 0.1 + 0.1 == 0.3False

Python 的 Float 遵循 IEEE 754 浮点算术标准[5],该标准以 64 位表示所有浮点数。因为浮点数有无限多位数,即不能用有限的位数来表达它们。

考虑time()这个函数的主要目的,是它表示的是现在的实际时间。它以自给定时间点(称为纪元)以来的秒数来表示函数。time()返回的数字很大,这意味着可用的数字较少,因而分辨率会受到影响。简而言之, time()无法测量纳秒级差异:

>>> import time>>> t = time.time()>>> t1564342757.0654016>>> t + 1e-91564342757.0654016>>> t == t + 1e-9True

一纳秒是十亿分之一秒。上面代码中,将纳秒添加到参数 t ,他并不会影响结果。与 time() 不同的是,perf_counter() 使用一些未定义的时间点作为它的纪元,它可以使用更小的数字,从而获得更好的分辨率:

>>> import time>>> p = time.perf_counter()>>> p11370.015653846>>> p + 1e-911370.015653847>>> p == p + 1e-9False

众所周知,将时间表示为浮点数是非常具有挑战的一件事,因此 Python 3.7 引入了一个新选项:每个时间测量函数现在都有一个相应的 _ns 函数,它以 int 形式返回纳秒数,而不是以浮点数形式返回秒数。例如,time() 现在有一个名为 time_ns() 的纳秒对应项:

import timetime.time_ns()
1564342792866601283

整数在 Python 中是无界的,因此 time_ns() 可以为所有永恒提供纳秒级分辨率。同样,perf_counter_ns() 是 perf_counter() 的纳秒版本:

>>> import time>>> time.perf_counter()13580.153084446>>> time.perf_counter_ns()13580765666638

我们注意到,因为 perf_counter() 已经提供纳秒级分辨率,所以使用 perf_counter_ns() 的优势较少。

注意: perf_counter_ns() 仅在 Python 3.7 及更高版本中可用。在 Timer 类中使用了 perf_counter()。这样,也可以在较旧的 Python 版本上使用 Timer。

有两个函数time不测量time.sleep时间:process_time()和thread_time()。通常希望Timer能够测量代码所花费的全部时间,因此这两个函数并不常用。而函数 monotonic(),顾名思义,它是一个单调计时器,一个永远不会向后移动的 Python 计时器。

除了 time() 之外,所有这些函数都是单调的,如果调整了系统时间,它也随之倒退。在某些系统上,monotonic() 与 perf_counter() 的功能相同,可以互换使用。我们可以使用 time.get_clock_info() 获取有关 Python 计时器函数的更多信息:

>>> import time>>> time.get_clock_info("monotonic")namespace(adjustable=False, implementation='clock_gettime(CLOCK_MONOTONIC)',monotonic=True, resolution=1e-09)>>> time.get_clock_info("perf_counter")namespace(adjustable=False, implementation='clock_gettime(CLOCK_MONOTONIC)',monotonic=True, resolution=1e-09)

注意,不同系统上的结果可能会有所不同。

PEP 418 描述了引入这些功能的一些基本原理。它包括以下简短描述:

  • time.monotonic():  超时和调度,不受系统时钟更新影响

  • time.perf_counter():基准测试,短期内最精确的时钟

  • time.process_time():分析进程的CPU时间

估计运行时间timeit

在实际工作中,通常会想优化代码进一步提升代码性能,例如想知道将列表转换为集合的最有效方法。下面我们使用函数 set() 和直接花括号定义集合 {...} 进行比较,看看这两种方法哪个性能更优,此时需要使用 Python 计时器来比较两者的运行速度。

>>> from timer import Timer>>> numbers = [7, 6, 1, 4, 1, 8, 0, 6]>>> with Timer(text="{:.8f}"):... set(numbers)...{0, 1, 4, 6, 7, 8}0.00007373>>> with Timer(text="{:.8f}"):... {*numbers}...{0, 1, 4, 6, 7, 8}0.00006204

该测试结果表明直接花括号定义集合可能会稍微快一些,但其实这些结果非常不确定。如果重新运行代码,可能会得到截然不同的结果。因为这会受计算机的性能和计算机运行状态所影响:例如当计算机忙于其他任务时,就会影响我们程序的结果。

更好的方法是多次重复运行相同过程,并获取平均耗时,就能够更加精确地测量目标程序的性能大小。因此可以使用 timeit 标准库,它旨在精确测量小代码片段的执行时间。虽然可以从 Python 导入和调用 timeit.timeit() 作为常规函数,但使用命令行界面通常更方便。可以按如下方式对这两种变体进行计时:

$ python -m timeit --setup "nums = [7, 6, 1, 4, 1, 8, 0, 6]" "set(nums)"2000000 loops, best of 5: 163 nsec per loop$ python -m timeit --setup "nums = [7, 6, 1, 4, 1, 8, 0, 6]" "{*nums}"2000000 loops, best of 5: 121 nsec per loop

timeit 自动多次调用代码以平均噪声测量。timeit 的结果证实 {*nums} 量比 set(nums) 快。

注意:在下载文件或访问数据库的代码上使用 timeit 时要小心。由于 timeit 会自动多次调用程序,因此可能会无意中向服务器发送请求!

最后,IPython 交互式 shell 和 Jupyter Notebook 使用 %timeit 魔术命令对此功能提供了额外支持:

In [1]: numbers = [7, 6, 1, 4, 1, 8, 0, 6]In [2]: %timeit set(numbers)171 ns ± 0.748 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)In [3]: %timeit {*numbers}147 ns ± 2.62 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

同样,测量结果表明直接花括号定义集合更快。在 Jupyter Notebooks 中,还可以使用 %%timeit cell-magic 来测量运行整个单元格的时间。

使用 Profiler 查找代码中的Bottlenecks

timeit 非常适合对特定代码片段进行基准测试。但使用它来检查程序的所有部分并找出哪些部分花费的时间最多会非常麻烦。此时我们想到可以使用分析器。

cProfile 是一个分析器,可以随时从标准库中访问它。可以通过多种方式使用它,尽管将其用作命令行工具通常是最直接的:

$ python -m cProfile -o download_data.prof download_data.py

此命令在打开分析器的情况下运行 download_data.py。将 cProfile 的输出保存在 download_data.prof 中,由 -o 选项指定。输出数据是二进制格式,需要专门的程序才能理解。同样,Python 在标准库中有一个选项 pstats!它可以在 .prof 文件上运行 pstats 模块会打开一个交互式配置文件统计浏览器。

$ python -m pstats download_data.profWelcome to the profile statistics browser.download_data.prof% help...

要使用 pstats,请在提示符下键入命令。通常你会使用 sort 和 stats 命令,strip 可以获得更清晰的输出:

download_data.prof% stripdownload_data.prof% sort cumtimedownload_data.prof% stats 10...

此输出显示总运行时间为 0.586 秒。它还列出了代码花费最多时间的十个函数。这里按累积时间 ( cumtime) 排序,这意味着当给定函数调用另一个函数时,代码会计算时间。

总时间 ( tottime) 列表示代码在函数中花费了多少时间,不包括在子函数中的时间。要查找代码花费最多时间的位置,需要发出另一个sort命令:

download_data.prof% sort tottimedownload_data.prof% stats 10...

可以使用 pstats了解代码大部分时间花在哪里,然后尝试优化我们发现的任何瓶颈。还可以使用该工具更好地理解代码的结构。例如,被调用者和调用者命令将显示给定函数调用和调用的函数。

还可以研究某些函数。通过使用短语 timer 过滤结果来检查 Timer 导致的开销:

download_data.prof% stats timer...

完成调查后,使用 quit 离开 pstats 浏览器。

如需更加深入了解更强大的配置文件数据接口,可以查看 KCacheGrind[8]。它使用自己的数据格式,也可以使用 pyprof2calltree[9] 从 cProfile 转换数据:

$ pyprof2calltree -k -i download_data.prof

该命令将转换 download_data.prof 并打开 KCacheGrind 来分析数据。

这里为代码计时的最后一个选项是 line_profiler[10]。cProfile 可以告诉我们代码在哪些函数中花费的时间最多,但它不会深入显示该函数中的哪些行最慢,此时就需要 line_profiler 。

注意:还可以分析代码的内存消耗。这超出了本教程的范围,如果你需要监控程序的内存消耗,可以查看 memory-profiler[11] 。

行分析需要时间,并且会为我们的运行时增加相当多的开销。正常的工作流程是首先使用 cProfile 来确定要调查的函数,然后在这些函数上运行 line_profiler。line_profiler 不是标准库的一部分,因此应该首先按照安装说明[12]进行设置。

在运行分析器之前,需要告诉它要分析哪些函数。可以通过在源代码中添加 @profile 装饰器来实现。例如,要分析 Timer.stop(),在 timer.py 中添加以下内容:

@profiledef stop(self) -> float:# 其余部分不变

注意,不需要导入profile配置文件,它会在运行分析器时自动添加到全局命名空间中。不过,我们需要在完成分析后删除该行。否则,会抛出一个 NameError 异常。

接下来,使用 kernprof 运行分析器,它是 line_profiler 包的一部分:

$ kernprof -l download_data.py

此命令自动将探查器数据保存在名为 download_data.py.lprof 的文件中。可以使用 line_profiler 查看这些结果:

$ python -m line_profiler download_data.py.lprofTimer unit: 1e-06 sTotal time: 1.6e-05 sFile: /home/realpython/timer.pyFunction: stop at line 35# Hits Time PrHit %Time Line Contents=====================================...

首先,注意本报告中的时间单位是微秒(1e-06 s)。通常,最容易查看的数字是 %Time,它告诉我们代码在每一行的函数中花费的总时间的百分比。

到此,关于“如何用装饰器扩展Python计时器”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

如何用装饰器扩展Python计时器

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

如何用装饰器扩展Python计时器

这篇文章主要介绍“如何用装饰器扩展Python计时器”,在日常操作中,相信很多人在如何用装饰器扩展Python计时器问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何用装饰器扩展Python计时器”的疑惑有所
2023-07-06

怎么利用装饰器扩展Python计时器

这篇文章主要介绍“怎么利用装饰器扩展Python计时器”,在日常操作中,相信很多人在怎么利用装饰器扩展Python计时器问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么利用装饰器扩展Python计时器”的疑
2023-07-02

如何利用上下文管理器扩展Python计时器

本文小编为大家详细介绍“如何利用上下文管理器扩展Python计时器”,内容详细,步骤清晰,细节处理妥当,希望这篇“如何利用上下文管理器扩展Python计时器”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。一个 Py
2023-07-02

python如何用使用装饰器统计函数的耗时

小编给大家分享一下python如何用使用装饰器统计函数的耗时,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!装饰器装饰器是一个装饰函数的函数,能够在不改变函数源码和
2023-06-17

怎么用上下文管理器扩展Python计时器

本文小编为大家详细介绍“怎么用上下文管理器扩展Python计时器”,内容详细,步骤清晰,细节处理妥当,希望这篇“怎么用上下文管理器扩展Python计时器”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。一个 Pyth
2023-07-06

Python中如何使用装饰器?

类方法和静态方法有点相似,他们都推荐使用类来调用(其实也可以使用对象来调用)定义类方法—使用@classmetho修饰(函数装饰器)—方法的第一个参数定义为cls(class的缩写),用类调用该方法时该参数会自动绑定定义静态方法—使用@st
2023-01-31

详解Java如何通过装饰器模式扩展系统功能

这篇文章主要为大家详细介绍了Java如何通过装饰器模式扩展系统功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
2023-05-16

如何使用Python装饰器Decorator

本篇内容介绍了“如何使用Python装饰器Decorator”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成! 1. 叠加使用Python装饰器
2023-06-15

如何使用Python的装饰器

这篇文章将为大家详细讲解有关如何使用Python的装饰器,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。1.定义及使用例1:装饰器定义: def 装饰器函数(外部函数): d
2023-06-29

如何使用装饰器

本篇内容主要讲解“如何使用装饰器”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何使用装饰器”吧!1. 常规的装饰器下面这是一个最简单的装饰器示例,在运行 myfunc 函数的前后都会打印一条日
2023-06-15

Python中如何浅谈装饰器

本篇文章给大家分享的是有关Python中如何浅谈装饰器,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。一 装饰器是什么 装饰器是一个用于封装函数或者类的代码工具,显式地将封装
2023-06-04

如何在Python中使用@property装饰器

这期内容当中小编将会给大家带来有关如何在Python中使用@property装饰器,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。一、property() 函数讲解了解 @property 装饰器之前,我们
2023-06-15

如何在python中使用类装饰器

这篇文章将为大家详细讲解有关如何在python中使用类装饰器,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。python有哪些常用库python常用的库:1.requesuts;2.scrap
2023-06-14

python中的装饰器该如何使用

目录1. 需求是怎么来的2. 以不变应万变,是变也3. 最大限度地少改动4.对带参数的函数使用装饰器5. 给装饰器参数6.带类参数的装饰器7. 对一个函数应用多个装饰器8. 作为一个类1. 需求是怎么来的装饰器的定义很是抽象,我们来看一个小
2022-06-02

如何在Python 中使用@lazyprop 装饰器

本篇文章为大家展示了如何在Python 中使用@lazyprop 装饰器,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。安装pip install lazyprop例子1from lazyprop i
2023-06-15

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录