原视频地址:Anthony Shaw - Wily Python: Writing simpler and more maintainable Python - PyCon 2019
要想写出更简单易懂、可维护的代码,我们首先当然得知道如何评估代码的复杂度。通过代码行数吗,肯定是不能的,比如下面两断代码,并不能说第二段比第一段更简单、更高级,因为第一段代码的可读性更强,我们一眼就能知道它在干什么。
下面介绍一下更加科学的评估方法。另外你没必要知道具体怎么计算,只要知道大概的意思就行。
评估代码复杂度的科学方案
Cyclomatic complexity(循環複雜度)
维基百科页面:en.wikipedia.org/wiki/Cyclom…
简单来说,Cyclomatic complexity就是一段代码独立路径可能性的总数目。如果没有 if语句、for 循环这些 controll flow 语句,代码就只有一条路径,那么复杂度就是1。如果有一条单条件if语句,复杂度就是2。两条嵌套的 if 语句,复杂度就是3。
维基中还给出了严格的数学定义,把一段代码的控制流程看作是一个图,这里不细讲了。
下面这段代码来自于 Python standard library,有很多个 if 判断,Cyclomatic complexity比较高。
更加形象点,假如我们把代码用一张纸打印出来,然后沿着缩进画一条曲线,如果这条曲线是一条蜿蜒曲折陡峭的山坡的话,那这段代码的Cyclomatic complexity就相对较高。
为什么我们的代码会有这么多 if?
git 可以通过git blame
(好形象的指令)查看某段特定的代码究竟是谁写的。很多时候遇到了 bug,修复者为了不 break 之前的代码,往往会加一个 if 条件判断,于是大家你加一个 if,我加一个 if,代码的复杂度就这么提高了。
代码的复杂度就是这么一点一点积累起来的。
就像上面这张图一样。
Halstead Matrix
维基百科页面:en.wikipedia.org/wiki/Halste…
计算公式如下:
比如下面这段 c 代码:
Maintainability 指数
把前面提到的这些组合起来,得到了最终的指数,从0-100分,分为4个等级。
现成的计算工具
randon
github 地址:github.com/rubik/radon
通过pip install radon
即可安装。
简单指令:
radon mi path -s
复制代码
这就可以查看此目录下所有 py 文件的Maintainability 指数得分。 我对我的一个项目跑了一下,结果如下:
看起来代码复杂度还很不错嘛。
然后用Cyclomatic complexity指标跑一下:
randon cc path -s
复制代码
这个还会给出具体 block 的得分,我在我电脑上跑了一下,还是找出了一些复杂度较高的代码块。
图中前面的 F 表示的 function 的意思,后面的字母和数字是得分,越高表示复杂度越低。
更多信息看官方文档。
wily
github 地址:github.com/tonybaloney…
注:wily 要求你要分析的代码库是一个 git repository,因为他会分析你的 git 历史代码。
直接通过pip install wily
安装。
wily -help
:
第一步:在代码仓库运行wily build .
耐心等待 wily 分析完成,这会把数据写入到~/.wily/
目录。
wily report
wili diff filename
wily graph
wily index
wily pre-commit hooks
pre-commit 如何使用请参考上篇文章:用 pre-commit hook 解决 Python 项目编码规范。
第一次可能会比较慢。
repos:
- repo: local
hooks:
- id: wily
name: wily
entry: wily diff
verbose: true
language: python
additional_dependencies: [wily]
复制代码
总结一下
如果你有一个函数,最开始的时候很简单,随着项目进展,越来越多 edge case 被发现,最后你的函数就会 成为catch所有可能性的 "god class"。上文提到的工具后可以帮助你发现复杂度高的代码块。
如果你像我一样真正热爱计算机科学,喜欢研究底层逻辑,欢迎关注我的微信公众号: