How to Learn Python for Frank Hu?

不确定情况下的学习 Study under Uncertainty

提纲

  • 学习: 从校园到生活
  • 学习的幻想
  • 不确定情况下的学习思路

1. 学习: 从校园到生活

我们首先回想一下自己在学校(特别是中小学阶段)的学习: 学习目标(准备考试)和学习内容明确且关系紧密; 有经验丰富的老师专职讲授课程; 有大量练习和考试, 通过与标准答案对比提供明确反馈. 而当我们离开老师和学校的环境, 自己进行学习时, 面临的情况又是什么? 学习目标和内容常常十分笼统, 且很难把一个实践目标和与之对应的具体学习内容联系起来; 没有专业人士像中小学老师一样长期专职辅导; 学习效果的反馈周期往往很长, 甚至没有任何外显反馈, 学习之后很难找到"标准答案"来评价自己的学习效果.
也就是说, 从学习目标, 学习过程, 以及学习中的反馈三个方面来看, 我们在中小学的学习过程都经过了多年优化. 超高信噪比的学校学习模式在极好地完成了应试任务的同时, 却也让我们离真实生活中的学习越来越远. 我们有必要思考, 在高不确定性的真实环境中, 学校的学习模式还能否起到良好效果, 我们应该如何学习?

2. 学习的幻想

在开始探索正确的学习姿势之前, 我们不妨先看看几个广泛存在的对于学习的幻想.

2.1 "我学过之后就什么都会了"

我们在学校中学习的知识与考试的内容, 有着完美的对应关系. (如果没有对应好, 通常叫做超纲...老师和学生都会尽量避免这种情况出现) 因此我们常常会形成一种惯性: 学过知识之后, 我们就可以正确使用它, 解决我们的问题. 然而事实常常并非如此.

学习过程只是接触一个新知识的最初期阶段. 我们学的东西, 并不一定对应着我们想用它解决的问题. 现实世界的复杂多变让我们时常并不能在刚学习时就发现我们真正需要学习的是什么.
(学习者不应幻想自己全都会----首先要接受事实, 接受随时可能发现新问题) 不夸张地说, 在刚进入某个新领域时, 甚至要有随时重头来过的觉悟.

真正常见的学习形态常常是有些混乱和纠结的, 也许是下面这样:
twisted
目标-学习-反馈-修正学习方向-学习-反馈-修正学习方向-...(直至解决初始问题)
真实的学习过程也许更像是画一幅油画, 我们反复涂抹修改, 直到画出自己满意的作品.

而对于学习路径的考虑, 就引出了下面一个更大的幻想, 也许它就静静藏在我们内心深处.

2.2 "学习效率最重要"

也许是工业社会生产力空前发展的一个必然结果, 现今, 我们对于"效率"的追求, 也达到了空前的程度. "效率"甚至已经成为了我们解释一切问题的一个常用思路. 两个人看上去都在做同样的事情, 为什么结果不一样? 哦! 一定是他们的效率不一样!
学习, 作为人类的一种活动, 也不可避免地被套上了"效率"的外衣: 为什么她学习好? 因为她学习效率高. 为什么我考试之前总是复习不完? 因为我复习效率低. 烦死了, 今天没有效率, 怎么学习/做实验/写代码啊! ----这些话, 在我们身边出现的频率越来越高.

似乎有了"效率", 我们就能今天写出万行代码/博士毕业, 明天登上称霸硅谷/诺贝尔奖领奖台; 没有"效率", 我们的生活就如同被按了"暂停"按钮, 直到找到名为"效率"的按钮再按上一下, 它才能在某种意义上继续播放. 这也许是一种时代病. 在这样一种幻想之中, 存在一条完美的路径, 只要按照这个"效率最高"的姿势前进, 我们就所向披靡. 生活的"效率"甚至超过生活本身, 成为了人们追逐的首要目标.

与第一个幻想不同的是, 对学习效率的追求, 实际上合情合理. 效率高的学习者, 在相同时间内, 通常的确会有更多的学习成果. 但过分追求效率, 则是学习路上的一大心魔, 将带来很多"走火入魔"的风险.

追求效率很可能引发完美主义倾向: "效率"的学习是一帆风顺的, 因此经常遇到困难和错误的学习一定效率不高. 具有这样思维假定的学习者在遇到困难时, 就更容易产生对学习效率的自我怀疑, 从而把精力从学习本身分散到对效率的思考之中; 为了避免学习过程中出现"不效率"的结果, 他们时常只是浅尝辄止, 用看代码, 看视频等不会遇到困难的手段, 学习一些自己擅长的内容, 来获得看似"高效"的学习. 而当我们抛开这些学习者津津乐道的"效率", 回到他们最初的学习目的时, 会发现这些看似"效率"更高的行为, 可能只是隔靴搔痒.

上文已经讨论过, 由于对学习对象的不了解与现实世界的复杂性, 现实生活中的学习过程通常具有较低的信噪比和很大的不确定性. 因此在学习开始前和进行时, 我们都不可能勾勒出一条具有"最高效率"的路径. 而当我们事后回顾学习过程时, 对"高效"的心理期待又常常引发"我当时要是如何如何学习就好了"的完美主义幻想, 这无益于已经完成的学习过程, 还可能引起自尊降低, 甚至产生对后续学习的畏难情绪.

客观来说, 效率也许确实是学习过程中的一个重要因素, 但它本质上是后验的(也许一切成功学的问题也在于此). 因此虽然看上去很美(一个简单模型中, 效果 = 时间 * 效率), 但"效率"可提升的空间不大, 对于学习过程的帮助也极其有限. 对学习效率的苛求, 一方面并不现实, 另一方面还常常引发学习者的负面情绪, 总体上对学习有害无益. 有效关注学习效率, 也许应更多表现为学习后定期根据事实进行反省, 避免长期出现大方向的失误; 而非锱铢必较, 试图时刻处于最高效的学习状态.

3. 极简敏捷行动: 一种不确定情况下的学习思路

从上面的讨论中我们可以发现, 学校的学习模式与现实生活的情况相距甚远. 看上去长久以来的学习经验不但未必能帮到我们, 还可能留下了一个并不理想的学习习惯. 那么, 我们究竟应该怎样在不确定情况下学习呢?
有效的学习姿势, 首先需要符合现实. 不回避学习中不可避免的困难和错误, 也不否定学习者的尝试和创造力(即使很多尝试是失败的). 这种思路的要点, 一言以蔽之, 是在学习目标范围中, 尽量多进行对未知的探索----真正的学习活动, 尽量减少花费在启动和选择上的时间.
有效的学习姿势, 最好还能富有乐趣. 不确定性情况下的学习在难度提高的同时, 也常常为我们带来更多的乐趣. 每一次最微小的尝试, 结果都是未知的, 一旦取得成功, 我们会感觉到乐趣; 而当我们通过一段时间的学习, 创造性地解决一个实际问题时, 那种实现自己想法的幸福感, 也是对学习者的最大奖赏. 对不确定的探索, 是人类能想象出的最大冒险. 在不确定的学习过程中, 如何产生更多积极反馈, 也是值得我们思考的问题.

从最近一段时间的 python 学习和团队项目开发中, 我逐渐发现, 把软件工程中敏捷开发的基本思路应用于学习, 似乎是一个不错的选择. 也就有了极简敏捷行动这个学习思路:

  • 极简: 目的是多学习多行动. 足够简单, 避免启动困难, 选择困难.
  • 敏捷: 加快学习循环, 促进正反馈循环
  • 行动: 行动才是根本, 思考服务于行动

然而原理只是原理, 具体行动上怎么实现呢? 我们也许可以写出一页个人学习指南, 帮助我们通过系统化的思维方式, 减少面对不确定时的困惑. (本质思路是, 由于效率的后验性, 我们找不到最正确的学习姿势. 但可通过一些常识问题排除掉部分错误的学习姿势----对错的不对称性.)

下面是一个大略的提纲:

  1. 定义问题
  2. 分解问题, 寻求MVP
  3. 学习-测试-反馈循环
  4. 定期质控

3.1 定义问题

目标导向: 思考目标和问题; 通过具体定义目标, 我们从完全的不确定中, 把精力首先集中于某一方面.

一个可用的 checklist: 5W1H

值得指出的是, 在刚刚进入一个不确定的问题时, 我们定义出的问题很可能并不正确. 在质控过程中, 我们需要时常回顾目标和问题, 并做出必要的调整.

3.2 分解问题, 寻求MVP(minimal viable product)

定义出来的问题时常是很模糊的, 我们很难直接把它转化为一个具体行动. 因此, 为了切实解决一个相对较大的问题, 我们需要把它分解为一些小的问题, 再把具体的学习行动与之联系起来.

一个很有效的分解问题方法是黑箱模型.

以"抓取豆瓣网页图书名称"为例, 我们通过黑箱模型进行分解: 即把我们的处理方法先假想为一个黑箱, 通过输入(input)-黑箱/处理(process)-输出(output)把问题分解为几个部分, 来确定我们需要做什么.

对于抓取豆瓣网页图书名称:

  • 输入: 豆瓣图书网页
  • 黑箱/处理: 我们的程序
  • 输出: 网页中的图书名称

因此, 我们的处理方法(黑箱)需要实现的目的, 即把输入(豆瓣图书网页)转化为输出(网页中的图书名称).

实例: (ipy notebook 开发过程实例待增补) 最简化所有步骤:

  • 输入: 抓取一个任意的最简单网页 - 抓取已知网页 - 读取用户输入内容
  • 黑箱/处理: 在一个已知字符串抓取一个字母/单词(随便什么) - 抓取一个链接 - 抓取页面全部符合要求的链接
  • 输出: 输出 hello world - 输出一个已知链接 - 输出一堆链接 (原则上够用了) 值得指出的是, 通过建立标准输入输出文件范例(把三部分的时空独立外显化), 可独立开发几个部分

以上讨论的本质: 我们可通过时间和空间, 把一个复杂的问题分解为一连串独立的简单问题的组合. (时: 先得到网页, 才能抓取, 最后输出; 空: 存储网页和书名信息的数据结构彼此独立)

3.3 "学习-测试-反馈"循环

通过时空分解, 我们把一个相对大的问题分解为了一个马上可以动手做的很具体的小问题(MVP). 下面, 就到了通过学习, 解决这个小问题的时间. 具体的学习行为, 可以用"学习-测试-反馈"的模型来概括. 也就是说, 我们先针对问题, 进行一段时间的学习和尝试, 随后进行测试, 测试结果的反馈决定我们开始研究下一个问题(测试成功), 或者是分析目前不成功的原因(测试失败)

在这个模型之中, 我们特别强调测试和反馈. 在信息爆炸的当下, 学习资源已经远远超过了我们处理信息的能力, 通常并不是制约我们学习效果的主要原因. 而测试和反馈的缺乏, 才是我们需要特别考虑的. 主动寻求测试和反馈, 也许是高阶学习者的一大特点. 比如在初学写作时, 有的学习者用自己的翻译和名家翻译对照, 或用自己的翻译-回译与原文对照, 从而通过同样内容的不同表述锤炼文字. 创造正反馈, 以正反馈的乐趣克服启动障碍 在寻求反馈循环方面, 编程学习有着独特的优势. 因为程序设计的学习目标(实现某个功能或算法)通常极为明确, 且测试(运行代码)反馈(分析运行结果)速度快, 结果清晰. Python 课程学习中, ipython notebook 是一个良好正面例子. 通过快速尝试和代码演进, 可以不断从最小的代码片段开始, 叠加代码功能. 另外, 完整的学习过程也被记录在了 notebook 之中, 可用于后续分析总结.

3.4 多层次质控

多层次质控: 用理性日常行动(routine)减少大失误(基于经验的反省智慧)

  • 每日三句话
  • 半周/一周/更长期质控与调整

理性: 接受不完美/不确定的事实 自信: 相信可以解决问题--特别是某些技术领域 耐心: 在负面情绪(不可避免!)袭来时保持理性

总结: 一份极简敏捷行动的案头手册--针对 python 编程学习

以上思路整合为一张图, 就可以作为一个特定学习内容的案头手册(cheat sheet). 学习时放在手边, 每一个小的学习片段(对我通常是半小时), 或者遇到困难需要暂停时, 就回看一次.

wheel-of-python

通过参考案头手册, 进行极简敏捷行动, 我们可以减少在不确定情况下学习时的选择和判断, 从而极大降低了这些行为占用的时间和心智(很多时候我们就是在纠结的选择中失去了行动能力...). 对应地, 当我们把更多时间投入具体的学习过程, 就能形成更多的学习循环, 在不断上升的循环中, 享受自我成长的学习之乐.


尾注

  1. 题目是对 Judgment under Uncertainty: heuristics and biases 致敬
inbox

> March 经验也许是最好的老师, 但不是特别好的老师(经验并不完美, 不过也许并不存在完美的老师)

可优化的效率: 专注  
(也许有必要分解效率为专注度--可控; 学习方向选择--未知; 把精力放在设法提高专注度和学习时间上.)

真实 + 快乐 = 优雅  

如何加强学习之乐: 基本的小乐趣--构建正反馈; 深层的大趣味--创造之美(人之为人的独特幸福来源)

一言以蔽之, 怎么学都可以! (事实上, 绝大多数人的问题似乎并不在学习的具体姿势, 而在学习的基本问题--时间投入不足.)

一种更夸张的幻想----只看不练, 认为自己看过就会了...
编程学习是对此最大反证.
看过十遍别人的代码, 也不如自己写一遍, 运行一次. 只有自己写, 运行, 调试才能得到反馈, 学习过程的体验是不能被其它行为代替的.(...这也是学习时候一定要注重真实时间投入的一个重要原因?)


最基础的原则: 不应脱离现实  
另外, 接受"自己有很多不懂的地方"并不是坏事  
要有随时学习新事物的觉悟和信心(这也是信息加速流动的时代的基本技能)
行动方面(绝不只是编程呦!), 不要慌张, 先平静心态接受事实(也不过分解读), 再用自己的常识分解问题尝试解决  
也许应该总结为一种 "学习者态度"  

(每一个小的学习片段--通常半小时左右/或者遇到问题需要暂停--就回看一次)
0. 确定目标
1. 定义问题
  - 黑箱模型: input-process-output
2. 分解问题
  - 时空分解
  - 寻求 MVP
3. 从第一个 MVP 出发, "开发-测试-认知"
  - 过程中的事件: 遇到问题/bug/...
  - 遇到问题的常用姿势(google-stackoverflow-py doc-...)/智慧提问(问题是-我的尝试是-结果是)
4. 进行中的多层次质控

为什么写 cheat sheet
规范化--避免大失误
如果完全按照自己的想法随意行动, 常常会出现比较明显的失误...这些失误是可以避免的
不求最优化, 只求中高程度的效率(通过排查大错, 可以消除大失误)
另外, 规范化的行动似乎并不限制想象力.