Python 实用宝典
  • 首页
  • 文章
    • Python 量化投资
    • python 智能家居系列教程
    • Python 爬虫
    • Python 绘图
  • 系列教程
    • Python 教程
    • Python 机器学习教程
    • Celery 教程
  • 数据/源代码下载
  • 联系我们

如何逐行描述Python代码?

2021-08-11 知识问答 0 0 1.0K

问题:如何逐行描述Python代码?

我一直在使用cProfile来分析我的代码,并且效果很好。我还使用gprof2dot.py可视化结果(使其更加清晰)。

但是,cProfile(以及到目前为止我见过的大多数其他Python分析器)似乎仅在函数调用级别进行分析。当从不同位置调用某些函数时,这会引起混乱-我不知道调用#1还是调用#2占用了大部分时间。当所讨论的函数有六个层次的深度(从其他七个地方调用)时,情况甚至更糟。

如何获得逐行分析?

代替这个:

function #12, total time: 2.0s

我想看这样的东西:

function #12 (called from somefile.py:102) 0.5s
function #12 (called from main.py:12) 1.5s

cProfile确实显示了“转移”到父级的总时间,但是当您有许多层和相互连接的呼叫时,该连接也会丢失。

理想情况下,我希望有一个GUI可以解析数据,然后向我显示源文件以及每行的总时间。像这样:

main.py:

a = 1 # 0.0s
result = func(a) # 0.4s
c = 1000 # 0.0s
result = func(c) # 5.0s

然后,我可以单击第二个“ func(c)”调用,以查看该调用中占用的时间,与“ func(a)”调用分开。

那有意义吗?是否有任何收集此类信息的性能分析库?我错过了一些很棒的工具吗?

点击查看英文原文

I’ve been using cProfile to profile my code, and it’s been working great. I also use gprof2dot.py to visualize the results (makes it a little clearer).

However, cProfile (and most other Python profilers I’ve seen so far) seem to only profile at the function-call level. This causes confusion when certain functions are called from different places – I have no idea if call #1 or call #2 is taking up the majority of the time. This gets even worse when the function in question is six levels deep, called from seven other places.

How do I get a line-by-line profiling?

Instead of this:

function #12, total time: 2.0s

I’d like to see something like this:

function #12 (called from somefile.py:102) 0.5s
function #12 (called from main.py:12) 1.5s

cProfile does show how much of the total time “transfers” to the parent, but again this connection is lost when you have a bunch of layers and interconnected calls.

Ideally, I’d love to have a GUI that would parse through the data, then show me my source file with a total time given to each line. Something like this:

main.py:

a = 1 # 0.0s
result = func(a) # 0.4s
c = 1000 # 0.0s
result = func(c) # 5.0s

Then I’d be able to click on the second “func(c)” call to see what’s taking up time in that call, separate from the “func(a)” call.

Does that make sense? Is there any profiling library that collects this type of information? Is there some awesome tool I’ve missed?


回答 0

我相信这就是Robert Kern的line_profiler的目的。从链接:

File: pystone.py
Function: Proc2 at line 149
Total time: 0.606656 s

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
   149                                           @profile
   150                                           def Proc2(IntParIO):
   151     50000        82003      1.6     13.5      IntLoc = IntParIO + 10
   152     50000        63162      1.3     10.4      while 1:
   153     50000        69065      1.4     11.4          if Char1Glob == 'A':
   154     50000        66354      1.3     10.9              IntLoc = IntLoc - 1
   155     50000        67263      1.3     11.1              IntParIO = IntLoc - IntGlob
   156     50000        65494      1.3     10.8              EnumLoc = Ident1
   157     50000        68001      1.4     11.2          if EnumLoc == Ident1:
   158     50000        63739      1.3     10.5              break
   159     50000        61575      1.2     10.1      return IntParIO

希望有帮助!

点击查看英文原文

I believe that’s what Robert Kern’s line_profiler is intended for. From the link:

File: pystone.py
Function: Proc2 at line 149
Total time: 0.606656 s

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
   149                                           @profile
   150                                           def Proc2(IntParIO):
   151     50000        82003      1.6     13.5      IntLoc = IntParIO + 10
   152     50000        63162      1.3     10.4      while 1:
   153     50000        69065      1.4     11.4          if Char1Glob == 'A':
   154     50000        66354      1.3     10.9              IntLoc = IntLoc - 1
   155     50000        67263      1.3     11.1              IntParIO = IntLoc - IntGlob
   156     50000        65494      1.3     10.8              EnumLoc = Ident1
   157     50000        68001      1.4     11.2          if EnumLoc == Ident1:
   158     50000        63739      1.3     10.5              break
   159     50000        61575      1.2     10.1      return IntParIO

Hope that helps!


回答 1

您也可以使用pprofile(pypi)。如果要分析整个执行过程,则不需要修改源代码。您还可以通过两种方法来分析较大程序的子集:

  • 到达代码中的特定点时切换配置文件,例如:

    import pprofile
    profiler = pprofile.Profile()
    with profiler:
        some_code
    # Process profile content: generate a cachegrind file and send it to user.
    
    # You can also write the result to the console:
    profiler.print_stats()
    
    # Or to a file:
    profiler.dump_stats("/tmp/profiler_stats.txt")
  • 通过使用统计性能分析从调用堆栈异步切换性能分析(需要一种在考虑的应用程序中触发此代码的方法,例如信号处理程序或可用的工作线程):

    import pprofile
    profiler = pprofile.StatisticalProfile()
    statistical_profiler_thread = pprofile.StatisticalThread(
        profiler=profiler,
    )
    with statistical_profiler_thread:
        sleep(n)
    # Likewise, process profile content

代码注释输出格式非常类似于行分析器:

$ pprofile --threads 0 demo/threads.py
Command line: ['demo/threads.py']
Total duration: 1.00573s
File: demo/threads.py
File duration: 1.00168s (99.60%)
Line #|      Hits|         Time| Time per hit|      %|Source code
------+----------+-------------+-------------+-------+-----------
     1|         2|  3.21865e-05|  1.60933e-05|  0.00%|import threading
     2|         1|  5.96046e-06|  5.96046e-06|  0.00%|import time
     3|         0|            0|            0|  0.00%|
     4|         2|   1.5974e-05|  7.98702e-06|  0.00%|def func():
     5|         1|      1.00111|      1.00111| 99.54%|  time.sleep(1)
     6|         0|            0|            0|  0.00%|
     7|         2|  2.00272e-05|  1.00136e-05|  0.00%|def func2():
     8|         1|  1.69277e-05|  1.69277e-05|  0.00%|  pass
     9|         0|            0|            0|  0.00%|
    10|         1|  1.81198e-05|  1.81198e-05|  0.00%|t1 = threading.Thread(target=func)
(call)|         1|  0.000610828|  0.000610828|  0.06%|# /usr/lib/python2.7/threading.py:436 __init__
    11|         1|  1.52588e-05|  1.52588e-05|  0.00%|t2 = threading.Thread(target=func)
(call)|         1|  0.000438929|  0.000438929|  0.04%|# /usr/lib/python2.7/threading.py:436 __init__
    12|         1|  4.79221e-05|  4.79221e-05|  0.00%|t1.start()
(call)|         1|  0.000843048|  0.000843048|  0.08%|# /usr/lib/python2.7/threading.py:485 start
    13|         1|  6.48499e-05|  6.48499e-05|  0.01%|t2.start()
(call)|         1|   0.00115609|   0.00115609|  0.11%|# /usr/lib/python2.7/threading.py:485 start
    14|         1|  0.000205994|  0.000205994|  0.02%|(func(), func2())
(call)|         1|      1.00112|      1.00112| 99.54%|# demo/threads.py:4 func
(call)|         1|  3.09944e-05|  3.09944e-05|  0.00%|# demo/threads.py:7 func2
    15|         1|  7.62939e-05|  7.62939e-05|  0.01%|t1.join()
(call)|         1|  0.000423908|  0.000423908|  0.04%|# /usr/lib/python2.7/threading.py:653 join
    16|         1|  5.26905e-05|  5.26905e-05|  0.01%|t2.join()
(call)|         1|  0.000320196|  0.000320196|  0.03%|# /usr/lib/python2.7/threading.py:653 join

请注意,由于pprofile不依赖于代码修改,因此它可以分析顶级模块语句,从而可以分析程序启动时间(导入模块,初始化全局变量等所需的时间)。

它可以生成cachegrind格式的输出,因此您可以使用kcachegrind轻松浏览大结果。

披露:我是pprofile作者。

点击查看英文原文

You could also use pprofile(pypi). If you want to profile the entire execution, it does not require source code modification. You can also profile a subset of a larger program in two ways:

  • toggle profiling when reaching a specific point in the code, such as:

    import pprofile
    profiler = pprofile.Profile()
    with profiler:
        some_code
    # Process profile content: generate a cachegrind file and send it to user.
    
    # You can also write the result to the console:
    profiler.print_stats()
    
    # Or to a file:
    profiler.dump_stats("/tmp/profiler_stats.txt")
    
  • toggle profiling asynchronously from call stack (requires a way to trigger this code in considered application, for example a signal handler or an available worker thread) by using statistical profiling:

    import pprofile
    profiler = pprofile.StatisticalProfile()
    statistical_profiler_thread = pprofile.StatisticalThread(
        profiler=profiler,
    )
    with statistical_profiler_thread:
        sleep(n)
    # Likewise, process profile content
    

Code annotation output format is much like line profiler:

$ pprofile --threads 0 demo/threads.py
Command line: ['demo/threads.py']
Total duration: 1.00573s
File: demo/threads.py
File duration: 1.00168s (99.60%)
Line #|      Hits|         Time| Time per hit|      %|Source code
------+----------+-------------+-------------+-------+-----------
     1|         2|  3.21865e-05|  1.60933e-05|  0.00%|import threading
     2|         1|  5.96046e-06|  5.96046e-06|  0.00%|import time
     3|         0|            0|            0|  0.00%|
     4|         2|   1.5974e-05|  7.98702e-06|  0.00%|def func():
     5|         1|      1.00111|      1.00111| 99.54%|  time.sleep(1)
     6|         0|            0|            0|  0.00%|
     7|         2|  2.00272e-05|  1.00136e-05|  0.00%|def func2():
     8|         1|  1.69277e-05|  1.69277e-05|  0.00%|  pass
     9|         0|            0|            0|  0.00%|
    10|         1|  1.81198e-05|  1.81198e-05|  0.00%|t1 = threading.Thread(target=func)
(call)|         1|  0.000610828|  0.000610828|  0.06%|# /usr/lib/python2.7/threading.py:436 __init__
    11|         1|  1.52588e-05|  1.52588e-05|  0.00%|t2 = threading.Thread(target=func)
(call)|         1|  0.000438929|  0.000438929|  0.04%|# /usr/lib/python2.7/threading.py:436 __init__
    12|         1|  4.79221e-05|  4.79221e-05|  0.00%|t1.start()
(call)|         1|  0.000843048|  0.000843048|  0.08%|# /usr/lib/python2.7/threading.py:485 start
    13|         1|  6.48499e-05|  6.48499e-05|  0.01%|t2.start()
(call)|         1|   0.00115609|   0.00115609|  0.11%|# /usr/lib/python2.7/threading.py:485 start
    14|         1|  0.000205994|  0.000205994|  0.02%|(func(), func2())
(call)|         1|      1.00112|      1.00112| 99.54%|# demo/threads.py:4 func
(call)|         1|  3.09944e-05|  3.09944e-05|  0.00%|# demo/threads.py:7 func2
    15|         1|  7.62939e-05|  7.62939e-05|  0.01%|t1.join()
(call)|         1|  0.000423908|  0.000423908|  0.04%|# /usr/lib/python2.7/threading.py:653 join
    16|         1|  5.26905e-05|  5.26905e-05|  0.01%|t2.join()
(call)|         1|  0.000320196|  0.000320196|  0.03%|# /usr/lib/python2.7/threading.py:653 join

Note that because pprofile does not rely on code modification it can profile top-level module statements, allowing to profile program startup time (how long it takes to import modules, initialise globals, …).

It can generate cachegrind-formatted output, so you can use kcachegrind to browse large results easily.

Disclosure: I am pprofile author.


回答 2

您可以为此使用line_profiler软件包的帮助

1.首先安装软件包:

    pip install line_profiler

2.使用magic命令将包加载到python / notebook环境

    %load_ext line_profiler

3.如果要分析功能代码,
请执行以下操作:

    %lprun -f demo_func demo_func(arg1, arg2)

如果您按照以下步骤操作,您将获得包含所有详细信息的格式化输出:)

Line #      Hits      Time    Per Hit   % Time  Line Contents
 1                                           def demo_func(a,b):
 2         1        248.0    248.0     64.8      print(a+b)
 3         1         40.0     40.0     10.4      print(a)
 4         1         94.0     94.0     24.5      print(a*b)
 5         1          1.0      1.0      0.3      return a/b
点击查看英文原文

You can take help of line_profiler package for this

1. 1st install the package:

    pip install line_profiler

2. Use magic command to load the package to your python/notebook environment

    %load_ext line_profiler

3. If you want to profile the codes for a function then
do as follows:

    %lprun -f demo_func demo_func(arg1, arg2)

you will get a nice formatted output with all the details if you follow these steps :)

Line #      Hits      Time    Per Hit   % Time  Line Contents
 1                                           def demo_func(a,b):
 2         1        248.0    248.0     64.8      print(a+b)
 3         1         40.0     40.0     10.4      print(a)
 4         1         94.0     94.0     24.5      print(a*b)
 5         1          1.0      1.0      0.3      return a/b

回答 3

只是为了改善@Joe Kington的上述答案。

对于Python 3.x,请使用line_profiler:


安装:

pip install line_profiler

用法:

假设您具有该程序main.py及其中的功能fun_a(),fun_b()并且要针对时间进行分析;您将需要@profile在函数定义之前使用装饰器。例如

@profile
def fun_a():
    #do something

@profile
def fun_b():
    #do something more

if __name__ == '__main__':
    fun_a()
    fun_b()

可以通过执行shell命令来分析程序:

$ kernprof -l -v main.py

可以使用获取参数 $ kernprof -h

Usage: kernprof [-s setupfile] [-o output_file_path] scriptfile [arg] ...

Options:
  --version             show program's version number and exit
  -h, --help            show this help message and exit
  -l, --line-by-line    Use the line-by-line profiler from the line_profiler
                        module instead of Profile. Implies --builtin.
  -b, --builtin         Put 'profile' in the builtins. Use 'profile.enable()'
                        and 'profile.disable()' in your code to turn it on and
                        off, or '@profile' to decorate a single function, or
                        'with profile:' to profile a single section of code.
  -o OUTFILE, --outfile=OUTFILE
                        Save stats to <outfile>
  -s SETUP, --setup=SETUP
                        Code to execute before the code to profile
  -v, --view            View the results of the profile in addition to saving
                        it.

结果将在控制台上显示为:

Total time: 17.6699 s
File: main.py
Function: fun_a at line 5

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
    5                                           @profile
    6                                           def fun_a():
...

编辑:探查器的结果可以使用TAMPPA包进行解析。使用它,我们可以逐行获得所需的图 情节

点击查看英文原文

Just to improve @Joe Kington ‘s above-mentioned answer.

For Python 3.x, use line_profiler:


Installation:

pip install line_profiler

Usage:

Suppose you have the program main.py and within it, functions fun_a() and fun_b() that you want to profile with respect to time; you will need to use the decorator @profile just before the function definitions. For e.g.,

@profile
def fun_a():
    #do something

@profile
def fun_b():
    #do something more

if __name__ == '__main__':
    fun_a()
    fun_b()

The program can be profiled by executing the shell command:

$ kernprof -l -v main.py

The arguments can be fetched using $ kernprof -h

Usage: kernprof [-s setupfile] [-o output_file_path] scriptfile [arg] ...

Options:
  --version             show program's version number and exit
  -h, --help            show this help message and exit
  -l, --line-by-line    Use the line-by-line profiler from the line_profiler
                        module instead of Profile. Implies --builtin.
  -b, --builtin         Put 'profile' in the builtins. Use 'profile.enable()'
                        and 'profile.disable()' in your code to turn it on and
                        off, or '@profile' to decorate a single function, or
                        'with profile:' to profile a single section of code.
  -o OUTFILE, --outfile=OUTFILE
                        Save stats to <outfile>
  -s SETUP, --setup=SETUP
                        Code to execute before the code to profile
  -v, --view            View the results of the profile in addition to saving
                        it.

The results will be printed on the console as:

Total time: 17.6699 s
File: main.py
Function: fun_a at line 5

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
    5                                           @profile
    6                                           def fun_a():
...


EDIT: The results from the profilers can be parsed using the TAMPPA package. Using it, we can get line-by-line desired plots as plot


回答 4

PyVmMonitor有一个实时视图,可以在那里帮助您(您可以连接到正在运行的程序并从中获取统计信息)。

请参阅:http://www.pyvmmonitor.com/

点击查看英文原文

PyVmMonitor has a live-view which can help you there (you can connect to a running program and get statistics from it).

See: http://www.pyvmmonitor.com/


声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。
line-by-line profiling Python
Python实用宝典
分享 收藏 点赞(0)
上一篇
如何将SQL查询结果转换为PANDAS数据结构?
下一篇
Python函数作为函数参数吗?

相关文章

知识问答

如果仅功能B需要功能A,是否应在B内部定义A?[关闭]

已关闭。这个问题是基于观点的。它当前不接受答案。 想改善这个问题吗?更新问题,以...
4 年前 0 0 1.0K
知识问答

按名称将列移动到熊猫表的前面

这是我的df: Net Upper Lower Mid Zsore Answer...
4 年前 0 0 1.0K
知识问答

在对象数组而不是字符串数组上的Python string.join(list)

在Python中,我可以执行以下操作: >>> list = ...
4 年前 0 0 1.0K
知识问答

在Python中的特定位置添加字符串

Python中是否可以使用任何函数在字符串的某个位置插入值? 像这样: "365...
4 年前 0 0 1.2K
排行榜展示
1

Python 情人节超强技能 导出微信聊天记录生成词云

2

你不得不知道的python超级文献批量搜索下载工具

3

Python 流程图 — 一键转化代码为流程图

4

7行代码 Python热力图可视化分析缺失数据处理

5

Python 优化—算出每条语句执行时间

6

你的10W块放哪里能赚最多钱?

文章展示

为什么在Python 2.7中自愿使用印刷括号?

如何在Python中按多个键对对象排序?

什么是“ 1 ..__ truediv__”?Python是否具有..(“点点”)表示法语法?

获取引起异常的异常描述和堆栈跟踪,全部作为字符串

Python正则表达式找到所有重叠的匹配项?

Python 超简单爬取新浪微博数据 (高级版)

Python 实用宝典

Python 实用宝典,专注于Python教程、深度学习教程、机器学习教程、智能家居教程、数据分析教程、自动化、可视化、数据下载、训练数据下载、模型下载等领域。

快速导航

  • 个人中心
  • 标签云
  • 网址导航

关于本站

  • VIP介绍
  • 客服咨询
  • 推广计划

联系我们

如有BUG或建议可与我们在线联系或登录本站账号进入个人中心提交工单或邮件联系 admin@pythondict.com。
Copyright © 2023 Python 实用宝典 - All rights reserved
  • 首页
  • 用户中心
  • 会员介绍
  • QQ客服
  • 首页
  • 分类
  • 会员
  • 我的
Python 实用宝典
微信支付
请使用 微信 扫码支付