Boxx 一个快速调试 Python 代码的工具库 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
diyer22
V2EX    Python

Boxx 一个快速调试 Python 代码的工具库

  •  1
     
  •   diyer22 2018-06-22 01:28:56 +08:00 3946 次点击
    这是一个创建于 2671 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近写了一个提高 Python 调试效率的工具包 boxx ,目前快完工了, 先分享出来,欢迎大家多提意见,也希望大家能喜欢这个工具。


    先从打印开始介绍吧,打印变量是最简单、直接的 debug 方式, 那能不能更简单?

    Note: boxx.p 使用了 magic method, p/x 便会打印 x 并返回 x。这样便可以在任何地方打印,比如 例子中的 p/randint(0, 3) 就不需要新建变量便可直接打印

    在函数内运行 p(),便会将函数或 module 内的所有变量名和值一同打印(相当于快捷打印 locals())

    Note: 在函数内 import boxx.pp() 有相同的效果

    许多数情况下, 直接 print 无法获得调试的关键信息。比如变量是有很多属性的对象,numpy 等类型

    这时 就必须对变量进行分析, 方式有:

    1. 在调试处加上 print(x.text, x.code, np.hasinf(x),.np.hasnan(x))
    2. 设置断点进行分析

    方法 1 每改一次调试代码 都要运行整个代码, 不灵活,操作也繁琐。
    方法 2 中进入和退出 Debug console 比较麻烦,Debug console 本身也不太好用(没有自动补全功能)
    boxx.g 提供了一种新的方式,通过 g.name 可以将变量传到当前的 Python 交互终端

    变量传到 Python 终端后,就能对变量进行全面分析了,比如 使用tree,what 来分析
    Note:

    • gg 的意思是 to Global and log, 和 g 的用法一样, 但 gg 会在传输的同时打印变量.
    • 需要注意, 如果之前在终端中存在一样的变量名称,则变量的值会被新值覆盖.

    在函数内运行 g(),便会将函数 (或 module) 内的所有变量一同传到当前的 Python 交互终端

    这样 任何错误都可以在终端中复现和分析了。当然, 注意不要覆盖重要的全局变量。
    Note: 在函数内 import boxx.gg() 有相同的效果

    在实际开发调试中, 函数或 module 内可能含有非常多的变量 但我们只对几个变量感兴趣, with p, with g, with gg 可以使操作只作用于几个感兴趣的变量,只需把变量放入 with 结构中即可 :

    Note:

    • with p, with g, with gg 只作用于在 with 结构中进行赋值操作的变量.
    • 如果变量名在 with 前存在于 locals() 中, 同时 id(变量) 没有变化 , with 结构可能无法检测到该变量.

    总结一下,boxx 的调试工具可以汇总为一个表

    boxx 调试工具矩阵

    Note:

    • transport 操作是指 把函数内的变量传送到 Python interactive console 中
    • locals() 指 作用于函数或 module 内的所有变量
    • locals()_2: 当 boxx 未导入时, import boxx.{操作} 能等价于 from boxx import {操作};{操作}()

    在学习新框架或适配大佬代码时,经常会使用 print(x), dir(x), help(x), type(x) 来了解某个变量的各方面的信息 (变量可能是 值 /function/class/module 等),于是我写了一个 boox.what(x) 来全面了解"what is x?":
    Note: what(x) 通过打印 x 自己及x文档, 父类继承关系, 内部结构所有属性 来全面了解 x. 是 help(x) 的补充.


    说了这么多调试 再说一下性能调优

    测试代码性能时,计时很常用, 我写了一个方便的计时工具boxx.timeit 将想要计时的代码块放入 with timeit(): 中就可以计时了:

    此外 SnakeViz 是一个很棒的性能分析工具,SnakeViz 能够通过 cProfile 文件,来统计代码的函数调用情况,并可视化出代码的 火焰图。但是, 先生成 cProfile 文件,再运行 SnakeViz 的流程非常繁琐,我把这一套操作封装成了 boxx.performance 来简化流程:

    Note: performance 也支持字符串形式的 Python 代码.

    在进行密集运算和处理时 得写多进程的 Python 代码 来干 CPU 的每一个线程获得加速。但我觉得 Python 多进程的几个范式都不够方便,我参照 map 的思想和用法把多进程操作封装成 boxx.mapmp 函数(意思是"Map for Mulit Processing"). mapmpmap 有一样的用法, 只需把 map 替换为 mapmp 即可获得多进程加速:

    Note:

    • mapmppool 参数来控制进程数目,默认为 CPU 线程数目.
    • 在多进程程序中, 打印进度往往非常麻烦. mapmpprintfreq 参数能解决这个问题.
    • 如同 map 一样,mapmp 支持将多个参数输入函数,如mapmp(add, list_1, list_2)

    对于网络爬虫等高 IO 操作,boxx 还有个多线程版本的 map -- mapmt (意思是 "Map for Mulit Threading")。mapmt 用法和 mapmp 一样, 但没有多进程的诸多限制。

    在开发和适配代码时,会遇到一些复杂的 dict,list。boxx.tree 可以直观地展示复杂结构。


    大致就介绍这些 boxx 的这些功能吧,欢迎大家多提意见!

    项目信息

    GitHub 主页:https://github.com/DIYer22/boxx(内含有更多说明)

    教程:boxx 的教程是一个可执行的在线 Notebook。 也就是说,无需下载和运行任何代码,只需浏览器点击下面的链接,就可以在线执行 Notebook 教程中的代码块。
    => 可直接执行的在线教程

    13 条回复    2019-06-19 14:09:53 +08:00
    laike9m
        1
    laike9m  
       2018-06-22 02:57:30 +08:00
    我很喜欢第一个功能加 p/ 在任意位置打印
    what 那个功能我之前写过更好的,你直接用就行了: https://github.com/laike9m/pdir2
    有几个功能是不是和 ipdb 耦合得太紧了?不用 ipdb 或者 notebook 能用么?像火焰图和 boxx.p
    diyer22
        2
    diyer22  
    OP
       2018-06-22 03:26:18 +08:00
    @laike9m 前辈啊,之前和你的想法很接近,有想法后就直接动手实现了一个 `boxx.dira`( meaning `dira attribute`),后来又把能打印的信息都加上了 扩展成了 `boxx.what`。

    整个项目都不需要 `ipdb` 或 notebook,可以在原始 Python 里直接使用,由于我主要做科学计算 更喜欢在 IPython 里面调试。

    `boxx.p` 没有使用除了 `sys` 以外的包 火焰图用了标准库的 `cProfile`来产生调试文件 + `SnakeViz` 用浏览器可视化 `cProfile`文件
    laike9m
        3
    laike9m  
       2018-06-22 03:31:20 +08:00
    “ boxx.g 提供了一种新的方式,通过 g.name 可以将变量传到当前的 Python 交互终端”
    但用 pdb 调试的人(比如我),就不知道应该怎么用以及能不能用了
    diyer22
        4
    diyer22  
    OP
       2018-06-22 03:40:21 +08:00
    @laike9m 我是觉得 pdb 的 debug console 的体验和 IPython 差太多,才写了这个功能。平时调试 `script.py` 都是在 IPython console 里面运行 `%run script.py` 来运行再调试。

    P.S. 平时调试时,把整个 `local()` 复制出来的 `g()` 操作更常用
    laike9m
        5
    laike9m  
       2018-06-22 03:45:12 +08:00
    有很多情况下程序是没法用 python xxx.py 来运行的(比如公司里的 binary ),而 pdb 是支持的,这个时候不知道还能不能用 IPython,当然我对 IPython 并不熟
    diyer22
        6
    diyer22  
    OP
       2018-06-22 03:49:02 +08:00
    @laike9m python xxx.py 都无法运行 那还属于 Python 程序吗。。。。 好奇要如何运行。。。
    laike9m
        7
    laike9m  
       2018-06-22 03:53:43 +08:00
    @diyer22 有很复杂的 build system,最后生成一个自带 interpreter 的 binary,不会这样裸着运行 Python 文件的
    laike9m
        8
    laike9m  
       2018-06-22 03:58:18 +08:00
    diyer22
        9
    diyer22  
    OP
       2018-06-22 04:09:42 +08:00 via Android
    @laike9m 高端,涨姿势了。如果调试环境没有 Interactive console 能用的话,那应该用不上 boxx.g
    mmqc
        10
    mmqc  
       2018-06-22 08:48:12 +08:00 via Android
    收藏,有空看
    laike9m
        11
    laike9m  
       2018-06-22 14:21:30 +08:00
    @diyer22 我感觉如果没依赖 IPython 的东西,应该是能用的,毕竟 pdb 也是 interactive 调试。如果文档写清楚这点会更好。
    diyer22
        12
    diyer22  
    OP
       2018-06-22 14:24:46 +08:00
    @laike9m 好的 我会考虑强调这一点的,谢谢建议
    VVTA
        13
    VVTA  
       2019-06-19 14:09:53 +08:00
    进来学习下哈
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2498 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 15:45 PVG 23:45 LAX 08:45 JFK 11:45
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86