1. 1. 前言
  2. 2. 正文
  3. 3. 结语

前言

学习都是一个循序渐进的过程,一个事情反复去看,反复去敲代码,会在这个过程中不断地学到东西,而不是过一遍就完事儿了。尤其是比较好的文章是值得反复去阅读的。在不断阅读的过程中,能收获到很多新的知识,同时对这个事情的印象也会更加深刻。

现在学习 CS 的过程就是这样的,不断地去看新的知识,但是新的知识有时候很难理解的话,你需要第二天在回过头来看新的知识,继续从其中挖掘到新的内容,同时加深对这个知识的理解。廖雪峰的教程就值得反复阅读。比如 js 中的 promise 章节,第一次看看不懂没关系,第二天接着看,就会有新的收获,而且会突然间恍然大悟,说:哦,原来是这个意思。然后接着看,看到第三遍的时候,相信你已经对 promise 有了很深的理解,甚至可以自己写一篇类似的文章,告诉别人 promise 是怎么回事。我在看廖雪峰的 python 教程的时候也有同样的体会。

正文

在学习廖雪峰 python2.7 教程的过程中,有一个生成器章节。这个章节里有一个斐波那契数列(fibonaci)数列的生成器的写法。

def fib(max) {
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        a, b = b, a+b
        n = n + 1
}

这里面有一句话在第一次看这个章节的时候忽略了,虽然下面的评论里有关于这句话的讨论,但是当时对于 python 的理解,对于计算机执行语句的理解都不是很好。而且当时又急于快速学会 python 这门语言,所以就没有在意这句话。

这句话就是:a, b = b, a+b

为什么说这句话被忽略了,或者说这句话其实隐含着计算机计算过程的奥义呢?

因为在第一次看这个章节的时候,我想当然的认为,这就是很简单的,把 b 赋值给 a,然后把 a+b 的和赋值给 b。不就是这么简单的事情吗?

但是后来在 Coursera 上学习 Python for everybody 这门课程的时候,Charles 教授解释了关于 a = 1 这句话。这句话的意思是 find 1, and stick with a。那么如果按照这种方式来理解 a, b = b, a+b 的话,其实这个 fib 数列是有问题的。我们一句句来理解,将 b 的值赋给 a,那么此时 a === b,然后将 a+b 的值赋给 b,因为上面已经执行了一步 b 的值赋给 a,所以此时此时 a+b 相当于是 b+b,那么新生成的 b 的值是 2b。举例说明可能更清楚一些:

a = 2
b = 3

# 按照一般的思维来理解
a = b #此时 a = 3
b = a+b # 相当于是 3+3=6

按照上面这种思路,此时的 fib 数列三个数字分别是 2, 3, 6,但实际上应该是 2, 3, 5。那么按照按照一般的思路去理解这句话的话是错误的。

那么这句话到底应该怎么理解呢?

其实看下面的评论里,大家有对这句话的激烈讨论,各式各样的说法都有。其实很多人的理解也都可以,但是根据廖雪峰的说法,其实这个构成是创建了一个中间的 tuple 变量 t 的。那么其中的奥义在哪里呢?我觉得应该就是在这个逗号里。也就是说:

a, b = b, a+b 中两个逗号,表示这个计算过程是同时的,就是在保持原来的 a, b 不变的情况下进行的。这个过程是同时的,而不是分开进行的。或者按照讨论里有人的评论说的,是先计算右边然后再赋值给左边。也就是说在计算没有完成之前,a, b 的值是保留原来的值没有变化的。这个过程相当于是:

a, b = 3, 2+3 ==> a, b = 3, 5 ==> a = 3, b = 5

这样的话其实这个过程就是正确的了。

这两天又在看 coursera 上 python for everybody 这门课程的 data structure 这一门,chapter 10 里讲的是 tuple,在视频大约 6:00 的时候,Charles 讲解了一个案例,就是 tuples and assignment,举得例子就是和上面一样的

>>>(x, y) = (4, 'fred')
>>>print y
fred
# we can even omit the parenthesis

显然可以看得出来,上面我所纠结的过程其实是 tuple 造成的,也就是说 a, b = b, a+b 实际上就是 tuple 的赋值过程。这个理解和廖雪峰在下面的评论是一致的。所以说廖雪峰的解释才是对的。

结语

计算机博大精深,内容太广阔了,要想完全掌握可能在我有生之年,这短短的几十年都无法全部掌握,但是基础知识很重要。只有基础知识掌握了,你看别的东西才会一看就懂,才会融会贯通。同时知识的广度也要扩展开,只有知识的广度扩展开你的思维才不会局限在一种形式上面,才会打开,才会有类比,才会触类旁通。我现在依然在打基础和扩展知识广度的层面。我相信每天坚持有效的学习,一定会有一天对计算机能游刃有余,一定有一天会对计算机有深刻的了解。

最近在找工作,感觉其实难度还是很大的,很多的人对于转行学习的人有一些偏见。我只有通过自己的努力,不论是技术层面还是战略层面的努力,才能实现自己的梦想。

继续打好基础,扩展知识范围。从 js 到 python,已经开始扩展自己的广度了,从前端基本的知识到现在主流的 mv* 框架,比如 angular, react, vue等等,到爬虫,到后端的 node,python 等等。我觉得我又有了一个比较大的进步。目前还在学习 coursera 上面的 python for everybody 这个系列课程。感觉对于循环,判断,函数等等一些基本的知识又有了更新的理解。加油,和时间赛跑。争取在5年的时间内可以实现新的突破和跨越。

我自学了 angular,但是又想学习 react,有人说知识要有选择性。我觉得是的,但是我相信同时掌握两个框架也不是不可能的事情。不要给自己设置障碍和屏障。加油,快速的学习,突破自己。

再多讲一句,多和计算机玩才能熟悉计算机,本来不打算入手树莓派(Raspberry pi)的,但是在上 Python for everybody 这么课程的时候,Charles 总是拿出来 CPU 和 内存条,还有硬盘,而且拿出来之后你其实会对这个过程理解的更多一些。尤其第一次课程上 Charles 拿出来这些东西的实体的时候,我对这个过程就感觉自动理解的多了一些。既然如此,而树莓派又和普通的 pc 没什么区别,所以我还是决定入手一个,我相信看到硬件之后尽管不会对你让计算机有直接的理解,但是一定会刺激某一方面的大脑,让你对于计算机有一个更多的了解。在玩树莓派的过程中一定会更加深刻的理解计算机。


2017.3.30 first published