2019年1月23日星期三

好用的 Python Profile(性能/耗时分析)工具

Matlab的profile工具非常好用,在Python里似乎没有类似好用的工具。PyCharm Professional版自带profile工具,而Community版不自带profile工具,只能自寻profile方案。Visual Studio似乎可以profile,但那套工具太大,平时并不想打开写python项目。

Line_profiler需要在函数前添加@profile装饰器,这样的方式可能不够优雅便利。

目前我的profile方案如下:

第1步. 生成原始文件:用cProfile生成原始的性能分析文件

cProfile是Python默认的性能分析器,选它没错的。可以在python脚本里运行,例如:
import cProfile
import re
cProfile.run('re.compile("ccc")', filename='result.out')

 也可以在cmd里运行,例如:
python -m cProfile -o result.out  ccc.py

第2步. 表格化分析原始文件:用pstats表格化分析由cProfile生成的原始文件

cProfile生成的原始文件并不易读,需要借助其他工具来处理原始文件。pstats模块可以以表格化的方式来处理cProfile生成的原始文件。
# 创建Stats对象
p = pstats.Stats(file_path)
# 按照运行时间和函数名进行排序
# p.strip_dirs().sort_stats("cumulative", "name").print_stats(0.5)
p.strip_dirs().sort_stats("cumulative", "name").print_stats(30)
# 按照函数名排序,只打印前3行函数的信息, 参数还可为小数,表示前百分之几的函数信息
# 如果想知道有哪些函数调用了ccc
# p.print_callers(0.5, "ccc")
# 查看ccc()函数中调用了哪些函数
# p.print_callees("ccc")

第3步. 图形化分析原始文件:目前推荐snakeviz

pip安装snakeviz后,在Anaconda prompt里运行如下命令:
snakeviz result.out
然后就会在弹出一个snakeviz的本地网页,可以在网页上自由点击查看哪个代码最耗时,非常直观方便:
图片摘自snakeviz官网
其他图形化工具:我试过gprof2dot,感觉总体上不如snakeviz简单、直接、美观。简单方面,用gprof2dot前需要安装graphviz,安装完成后还需要把graphviz安装目录下的bin文件夹添加到环境路径Path,而snakeviz只需pip安装即可。直接、美观方面,gprof2dot会把结果生成为图片,图片效果不如snakeviz的网页美观,如果profile的脚本较为复杂的话,图片过大内容过于密集,很不方便查看。

目前我的Python Profile做法就是这样。

最后还是想说一句,Python作为免费软件,在Profile的便利和美化程度上确实没法跟收费软件Matlab相比(另外帮助文档也是Matlab远胜),人家收费还是有道理的。

代码截图可以更漂亮:推荐Carbon工具

Carbon(官网:carbon.now.sh)是个网站,专门用于生成漂亮的代码截图。譬如底下这张:


Carbon用起来非常简单,只需要登录网站 carbon.now.sh,把代码粘贴进去,选颜色、样式等,最后点击右侧的“Export”按钮即可导出漂亮的代码截图,操作非常方便。


当然我们也可以选择直接在本地的代码编辑器里截图,但截图效果显然比Carbon差了很多,下方是直接对着Pycharm截图的效果,明显不如本文开头的第一张图片美观。


说到代码在网页上的展示方式,除了代码截图外,另一种方式是用网页编辑器自带的代码模块。

说起这个,并非所有平台的编辑器都支持“代码模块”,例如百度百家号就不支持,作为替代,只能用“引用模块“来替代,但这样有两大问题:

(1)不支持语法高亮

(2)更严重的问题是,前后两行代码明明是两行,但在一些浏览器里这两行代码会连在一起,非常不好看

鉴于以上两个原因,“用网页编辑器自带的代码模块”只能是可望不可求,更通用的方案是代码截图,而用到代码截图的话,不妨试试可以让代码截图更漂亮的Carbon。

Python 一组缺失值(NaN)的和为0 还是 NaN?积为1还是NaN?

这是一个很可能会踩的坑!

在Python,MATLAB 等编程语言里缺失值通常用 NaN 来表示,NaN 是 Not a Number 的缩写。

维基百科对 NaN 的解释

假如有三个数,分别是 10、20 和 NaN,对它们求和,忽略 NaN 的求和(例如 Python 里的 numpy.nansum),那么毫无意外地,得到的值为 10 + 20 = 30



假如三个数全是 NaN,那么求和结果是?我们可能预期得到 NaN,但实际上,程序计算结果为0!



关于计算结果应当为 0 还是 NaN,网上有一些讨论,具体可参见上图中的链接,这里不详细展开。



我个人更倾向于返回值为 NaN。因为返回结果是 0 的话,我并不知道到底是原来有值,例如1、0、-1,然后加总等于0,还是因为三个数全是 NaN 导致计算结果为 0


另外,除了和为0,一组 NaN 的乘以等于 1,而非 NaN,这点也需要注意。


简单易用的Python发邮件工具:yagmail

在Python里发邮件,yagmail大概是目前最简单易用的方式。

yagmail的作者主页已经把教程写得很清楚了,这里我把自己尝试后的体会写下来。

第一步是在Python里安装yagmail,用 pip install yagmail 即可。

接下来开始发邮件了:



收件人可以设置多个,可以对每个收件人设置昵称,可以发送html格式的邮件,发送其他附件,也可以使图片在邮件正文显示,关于上述这些,这里就不多说了,可参见yagmail的作者主页。

这里我想说明的是“账号密码问题”。直接在代码里写明文的密码显然不安全,yagmail的作者推荐的方式是用keyring。

在操作yagmail之前,可以先配置账号密码,运行如下代码:


上述代码会把邮箱账号密码保存在电脑里。如果是Windows,账号密码的位置是“控制面板-凭据管理器-Windows凭据”,在这个位置下其实还可以看到Windows账户的登陆信息。

有了keyring存储的密码,这样以后发邮件就不用在yagmail明文输入密码了,我们先前的代码可以改为:

注意到此时已不需要填写密码了。

IPv6 的 fe80开头的地址

fe80开头的 ipv6 地址不是公网地址,没人给你分ip,自动协商的地址,通常无法用于上网。 现在各大运营商用的ipv6: 电信是240e开头的(240e::/20) 移动是2409开头的(2409:8000::/20) 联通是2408开头的(2408:8000::/20)