也谈如何阅读程序源代码

592 查看

这周完成了一个意料之外的工作,我把python的wtfroms, voluptuous,logging三个包的代码读了,还读得挺high的。
之前我一直觉得读源代码是件痛苦的事情,不过不知怎么的不怕了,还挺享受的。所以我总结了一下读代码的心得,分享一下。

阅读代码有两点最重要:

1. 理解。阅读程序最重要的是理解程序,包括几个方面:1)理解每行代码做了什么,2)理解作者设计的意图,3)考虑作者都没发现的问题。
2. 提出问题,解决问题。读到没有见过的库函数,遇到没有见过的语法,遇到没有见过的技术,先不要着急google,
先考虑一下你遇到的是什么问题,然后使用网络(google, stackoverflow)找答案,没有彻底解决的疑惑要用笔记下来,不放过疑问。

我现在来示范一下。

从wtforms开始,代码在此https://github.com/wtforms/wtforms

第一个遇到的问题,也是核心问题:

Q: wtforms是干什么的?
A: 它是解决html表单验证的工具。

(OK,可能你有更好的答案。不过在没读代码前,这可能是你能想到的最好的答案。当你对代码的理解加深了,你会有更好的答案的。)

我们来看一下代码的目录。

docs,tests这些辅助都不是核心,不重要。gitignore文件,travis配置文件,python setuptools文件都不重要,略过它们,找到重点,重点在wtforms文件夹。

进入这个目录。

第二个问题是了解作者是如何分割各个模块的?

如何分割模块就是作者的想法了,要读懂代码得了解他的想法。

如果一眼看不明白,可以找文档来读。http://wtforms.readthedocs.org/en/latest/

读完后就应该大致明白,wtforms分为几个关键的对象

  • form: 负责对表单建模
  • field: 负责建模每个表单的字段
  • validator: 负责验证每个字段。
  • widget: 负责在html上渲染。

所以我们看到在这个目录里

  • form.py
  • validators.py
  • fields
  • widgets

是要读的代码,其他可以先不看,因为相对来说不是核心。

我们从form.py开始 https://github.com/wtforms/wtforms/blob/1.0.4/wtforms/form.py

实事上即便是这文件也不是要全部读的。

首先看最上层的构筑,这段代码里面这些行是主结构:

这三行通过最后一行绑定到一起。

你看不懂第二?先猜一下FormMeta是继承自type类型的,看不懂第三行?找到了关键字metaclass,直接google “python metaclass” 查一下网上的资料。弄明白python metaclass。

同一级别的还有一行:

但是,似乎和前面三者没有关系,所以暂时忽略掉。

然后看下面一层的代码。你会发现有很多带有两个下划线的函数,它们的函数体都很短,
google 一下知道这些函数是处理如何取和存对象的属性的,而且没有什么复杂的操作,
我们现在的目的是搞明白form如何工作的,所以先忽略他们,到有需要的时候再看。
重要的是那些作者自己定义的函数。以及大块的函数,比如初始化函数__init__

找到了重点代码段,读就是了,理解每一行。

Q: 那么那些不是很重要的代码该怎么读?
A: 等需要用到的时候去读。阅读代码并不能真正理解代码,在使用的时候你会发现更多的问题,
所以需要依靠调试来理解代码。

幸好python是动态语言,而且有virtualenv,和DVCS,我只需要print语句就可以解决大多数的调试问题。
为了搞明白wtforms是怎么工作的,我边写代码,边调试了几个小时。

总结一下如何读代码:

实际上不难!

。。。。。。。还没完。。。。。。

@Philip_Tzou 向我推荐了voluptuous这个库 https://github.com/alecthomas/voluptuous

我吃惊得发现原来validator的实现可以用这样完全不同的思考方式。

wtforms使用的建模方法是将一个html表单看做是form object,每一个input标签是一个form field object,然后在每一个field object上进行验证操作,最后可以通过widget渲染成html元素。

而voluptuous使用了另一种思路,它没有对form建模,所以也没有form object,它只有验证器!你要做的是按照需要处理的对象来拼装同样模式的验证器。

所以我后来考虑了这两者思考方式的不同。

Q: wtform的作者为了解决什么问题?voluptuous的作者又为了解决什么问题?(记得我在示范开始的时候提的第一个问题了吗?)
A: wtform的作者要解决如何验证html form的问题,voluptuous的作者要解决的事如何验证任意python对象。虽然两个工具都能够用来

解决表单验证,但是前者更专注于网页的POST请求,所以程序要处理html页面渲染的问题,这算是相对重量级的应用场合。

另外作者考虑到要和ORM层的对接,甚至有了一个populate_obj这个函数。

而voluptuous的作者单纯对python object的验证可以用在轻量级的场合,比如ajax参数验证的情况。