Table of Contents:

Python的源码以及优秀的示例程序
https://github.com/python/
https://github.com/python/cpython/tree/master/Tools/demo

the-craft-of-selfteaching, by 李笑来

 前言

这本 “书” 是近些年我一直在做却没做完整的事情,讲清楚 “学习学习再学习”:
只不过,这一次我阐述地更具体 —— 不是 “学会学习”,而是 “学会自学” —— 这一点点的变化,让十多年前没写顺的东西,终于在这一次迎刃而解,自成体系。

 以前,我在写作课里讲,写好的前提就是 “Narrow down your topic” —— 把话题范围缩小缩小再缩小…… 这次算是给读者一个活生生的实例了罢。

最消耗生活质量的东西,就是焦虑
别人无法贩卖给你焦虑,是你自己焦虑 —— 是你自己在为自己不断积累越来越多的焦虑……

自学没有什么 “秘诀”。它是一门手艺,并且,严格意义上来讲,它只是一门手艺。
手艺的特点就是无需天分。手艺的特点就是熟练程度决定一切。从这一点上来看,自学这门手艺和擀饺子皮没什么区别 —— 就那点事,刚开始谁都笨手笨脚,但熟练了之后,就那么回事…… 而已。
一切与自学相关的技巧都是老生常谈

 如何证明你真的读过这本书?

通过git工具来记录

 P1A.为什么一定要掌握自学能力?

一句话解释清楚:

 没有自学能力的人没有未来。

有两个因素需要深入考虑:
 未来的日子还很长
 这世界进步得太快

我有个观察:

 很多人都会不由自主地去复刻父母的人生时刻表。
 比如,你也可能观察到了,父母晚婚的人自己晚婚的概率更高,父母晚育的人自己晚育的概率也更高……
 但是,这很危险,因为很多人完全没有意识到自己所面临的人生,与父母所面临的人生可能完全不一样 —— 各个方面都不一样。

都说,人要有一技之长。那这一技究竟应该是什么呢?

 自学能力是唯一值得被不断磨练的长技。
磨练出自学能力的好处在于,无论这世界需要我们学什么的时候,我们都可以主动去学,并且还是马上开始,不需要等别人教、等别人带。

 P1B.为什么把编程当作自学的入口?

许多年前,不识字,被称为文盲……
后来,人们反应过来了,不识英文,也是文盲,因为科学文献的主导语言是英文,读不懂英文,什么都吃不上热乎的;等菜好不容易端上来了吧,早就凉了不说,味道都常常会变……
再后来,不懂基本计算机操作技能的,也算是文盲,因为他们无论做什么事情,效率都太低下了,明明可以用快捷键一下子完成的事情,却非要手动大量重复……
到了最近,不懂数据分析的,也开始算作文盲了。许多年前人们惊呼信息时代来了的时候,其实暂时体会不到什么太多的不同。然而,许多年过去,互联网上的格式化数据越来越多,不仅如此,实时产出的格式化数据也越来越多,于是,数据分析不仅成了必备的能力,而且早就开始直接影响一个人的薪资水平。

编程入门的门槛之所以高,有个比较特殊的原因:
它的知识点结构不是线性的。
比如,几乎所有的 Python 编程书籍上来就举个例子: print('Hello, world!')
姑且不管这个例子是否意义非凡或者意义莫名,关键在于,print() 是个函数,而函数这个概念,不可能一上来就讲清楚,只能在后面若干章之后才开始讲解……
这种现象,可以借用一个专门的英文概念,叫做 “Forward References” —— 原本是计算机领域里的一个术语。为了配合当前的语境,姑且把它翻译为 “前置引用” 或 “过早引用”。也行。
学校里的课本,都很严谨 —— 任何概念,未经声明就禁止使用。所以,学完一章,就能学下一章;跳到某一章遇到不熟悉的概念,往前翻肯定能找到……
在学校里习惯了这种知识体系的人,离开学校之后马上抓瞎 —— 社会的知识结构不仅不是这样的,而且几乎全都不是这样的。工作中、生活里,充满了各式各样的 “过早引用”。
为什么总是要到多年以后你才明白父母曾经说过的话那么有道理?
为什么总要到孩子已经长大之后才反应过来当初自己对孩子做错过很多事情?为什么在自己成为领导之前总是以为他们只不过是在忽悠你?
为什么那么多人创业失败了之后才反应过来当初投资人提醒的一些观念其实是千真万确的?
—— 因为很多概念很多观念是 “过早引用”,在当时就是非常难以理解……

 P1C.只靠阅读习得新技能

绝大多数情况下,没人能教你,也不一定有人愿意教你…… 到最后,你想学会或你必须学会什么东西的时候,你只能靠阅读! —— 因为其实你谁都靠不上……

 P1D.开始阅读前的一些准备

 P1E1.入口

程序这个东西,不过是按照一定顺序完成任务的流程(Procedures)。除了可以 “按照顺序执行任务” 之外,还可以 “根据不同情况执行不同的任务”,比如,“如果条件尚未满足则重复执行某一任务”。

将布尔运算作为教授编程的入口
乔治・布尔 布尔运算 布尔值 逻辑操作符 布尔运算操作符 流程控制

 P1E2.值及其相应的运算

在编程语言中,总是包含最基本的三种数据类型:

  布尔值(Boolean Value)
 
 数字(Numbers):整数(Int)、浮点数(Float)、复数(Complex Numbers)
 * 字符串(Strings)

有个函数,type(),可以用来查看某个值属于什么类型
将字符串转换为数字用 int()、float();
将数字转换成字符串用 str();
将整数转换成浮点数字用 float();
将浮点数字转换成整数用 int();

Here are most of the built-in objects considered False

  constants defined to be false: None and False.
 
 zero of any numeric type: 00.00jDecimal(0)Fraction(0, 1)
 * empty sequences and collections: ''()[]{}set()range(0)

 P1E3.流程控制

if  for  while

 P1E4.函数

 P1E5.字符串

标示一个字符串,有 4 种方式,用单引号、用双引号,用三个单引号或者三个双引号
f-string 与 str.format() 的功用差不多,只是写法简洁一些 —— 在字符串标示之前加上一个字母 f

name = 'John'
age = 25
f'{name} is {age} years old.'
f'{name} is a grown up? {age >= 18}'

# 输出
'John is 25 years old.'
'John is a grown up? True'

 P1E6.数据容器

list tuple set dict

 P1E7.文件

 P1F.如何从容应对含有过多 “过早引用” 的知识?

 不懂也要硬着头皮读完

读不懂也要读完,然后重复很多遍
有经验的读书者,拿来一本书开始自学技能的时候,他会先翻翻目录(Table Of Contents),看看其中有没有自己完全没有接触过的概念;然后再翻翻术语表(Glossary),看看是否可以尽量理解;而后会看看索引(Index),根据页码提示,直接翻到相关页面进一步查找…… 在通读书籍之前,还会看看书后的参考文献(References),看看此书都引用了哪些大牛的书籍,弄不好会顺手多买几本。
这样做,显然是老到 —— 这么做的最大好处是 尽力消解了大量的过早引用,为自己减少了极大的理解负担。
所以,第一遍的正经手段是 “囫囵吞枣地读完”。

 磨练 “只字不差” 的能力

“只字不差地阅读” 是所有自学能力强的人都会且都经常使用的技能。尤其是当你在阅读一个重要概念的定义之时,你就是这么干的:定义中的每个字都是有用的,每个词的内涵外延都是需要进行推敲的,它是什么,它不是什么,它的内涵外延都是什么,因此,在使用的时候需要注意什么……
所谓的自学能力差,很可能最重要的坑就在这里:

 每一次学习新技能的时候,很多人只不过是因为做不到只字不差地阅读,于是总是会错过很多细节;于是,最终就好像 “看了另外一个山寨版电影一样”,实际上 “习得了另外一个山寨版技能”……

 好的记忆力很重要

就算读不懂也要读完 的更高境界,是 就算不明白也要先记住
人们普遍讨厌 “死记硬背”…… 不过,说实话,这很肤浅。虽然确实也有 “擅长死记硬背却就是什么都不会的人”,但是,其实有更多记忆力强的人,实际上更可能是 “博闻强识”。
记忆力这个东西,有一百种方法去弥补 —— 比如,最明显、最简单的办法就是 “好记性不如烂笔头”,其次就是重复
所以,在绝大多数正常情况下,所谓的 “记不清、记不住、甚至干脆忘了”,都只不过是懒的结果

 尽快开始整理归纳总结

第一遍囫囵吞枣之后,马上就要开始 “总结、归纳、整理、组织 关键知识点” 的工作。自己动手完成这些工作,是所谓学霸的特点。他们只不过是掌握了这样一个其他人从未想过必须掌握的简单技巧。他们一定有个本子,里面是各种列表、示意图、表格 —— 这些都是最常用的知识(概念)整理组织归纳工具,这些工具的用法看起来简单的要死。
可实际上,自己动手做做就知道了 —— 整理、归纳、组织,再次反复,是个相当麻烦的过程。非学霸们自己不动手做的真正原因只不过是:嫌麻烦、怕麻烦。一个字总结,就是,懒!可是,谁愿意承认自己懒呢?没有人愿意。于是,都给自己找个冠冕堂皇的理由,比如,上面说的 “反正别人已经做好了,我为什么还要再做一遍呢?” 再比如,“这世界就是懒人推进的!”
自学能力强的人有个特点,就是不怕麻烦。小时候经常听到母亲念叨,“怕麻烦!那还活着干嘛啊?活着多麻烦啊!” —— 深刻。

 先关注使用再研究原理

不管怎么样,先用起来,反正,研究透原理,不可能马上做到,需要时间漫漫。
用错了没关系,改正就好。用得不好没关系,用多了就会好。只要开始用起来,理解速度就会加快 —— 实践出真知,不是空话。

 尊重前人的总结和建议

Python 中有一个概念叫 PEP,Python Enhancement Proposals,必须找时间阅读,反复阅读,牢记于心:

 P1G.官方教程:The Python Tutorial

请牢记且遵守这个原则:第一查询对象只能是官方文档
所以,当我用 Google 查询的时候,经常使用这样的格式:
 site:python.org
有时甚至会指定在哪个目录里搜索:
bytes site:python.org/3/library,你试试这个连接:bytes site:python.org/3/library

 P2A.笨拙与耐心

自学是门手艺,编程很大程度上也是一门手艺,掌握它在绝大多数情况下与天分智商全无关系 —— 很多人是在十来岁的时候学会编程的基本技能的。所有的手艺,最基本特征就是:主要靠时间

预算观念非常重要 —— 这个观念的存在与否,成熟与否,基本上决定一个人未来的盈利能力。
大多数人对此不仅不成熟,甚至干脆没有预算观念!—— 这也是为什么绝大多数人不适合创业的最根本原因。
不夸张地讲,未来的你只需要恪守一个原则,就很可能会因此超越 99% 的人:

 绝对不做预算不够的事情。

 P2B.刻意练习

手艺这个东西,尤其需要刻意练习。我们说,手艺么,主要是靠时间…… 这里的 “时间”,准确地讲,就是 “刻意练习” 的时间,而不是任何时间。而且要刻意思考哪些地方我应该去刻意练习。

生活中可能有好多地方是需要刻意练习的,应对策略很简单:准备个专门的地方记录,一旦遇到什么 疑似需要刻意练习 的点,就顺手记录在那里以防不小心忘记或者不小心遗漏。而后有时间的时候就拿出来看看,排列一下优先级,琢磨一下刻意练习的方式,而后找时间刻意练习,如此这般,做到 尽量不混日子……

人们常说:

 凡事,就怕琢磨……
那些高手,无一例外都是善于琢磨的人…… 可是,他们在琢磨什么呢?为什么他们会琢磨那些事呢?

 P2C.为什么从函数开始?

 P2D1.关于参数(上)

 为函数取名

用小写字母+下划线

查看关键字

import keyword
keyword.kwlist               # 列出所有关键字
keyword.iskeyword('if')      # 查询某个词是不是关键字

 P2D2.关于参数(下)

函数内部return返回值是 None,当 None 被当作布尔值对待的时候,相当于是 False
Order of Arguments

 1. Positional
 1. Arbitrary Positional
 1. Keyword
 1. Arbitrary Keyword

 P2D3.别名与匿名

def _is_leap(year):
    return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)


year_leap_bool = _is_leap
year_leap_bool              #<function __main__._is_leap(year)>
year_leap_bool(800)         # _is_leap(800) -> True


id(year_leap_bool)          # id() 这个函数可以查询某对象的内存地址
id(_is_leap)                # year_leap_bool 和 _is_leap 其实保存在同一个地址中,也就是说,它们是同一个对象。
add = lambda x, y: x + y
add(3, 5)

 P2D4.递归函数

递归函数三原则

 1. 根据定义,递归函数必须在内部调用自己;
 2. 必须设定一个退出条件;
 3. 递归过程中必须能够逐步达到退出条件……

 P2D5.函数的文档(docstring)

你在调用函数的时候,你像是函数这个产品的用户
而你写一个函数,像是做一个产品,这个产品将来可能会被很多用户使用 —— 包括你自己。
把函数的 “产品说明书” 当作语言内部的功能,这也是为什么 Python 有 Sphinx 这种工具,而绝大多数其他语言没有的原因之一罢。
在函数定义内部,我们可以加上 Docstring;将来函数的 “用户” 就可以通过 help() 这个内建函数,或者 .__doc__ 这个 Method 去查看这个 Docstring,即,该函数的 “产品说明书”。

def is_prime(n):
    """
    Return a boolean value based upon
    whether the argument n is a prime number.
    """
    if n < 2:
        return False
    if n == 2:
        return True
    for m in range(2, int(n**0.5)+1):
        if (n % m) == 0:
            return False
    else:
        return True

help(is_prime)
print(is_prime.__doc__)
is_prime.__doc__

Docstring 如若存在,必须在函数定义的内部语句块的开头,也必须与其它语句一样保持相应的缩进(Indention)。Docstring 放在其它地方不起作用:

 书写 Docstring 的规范

规范,虽然是人们最好遵守的,但其实通常是很多人并不遵守的东西。
既然学,就要像样 —— 这真的很重要。所以,非常有必要认真阅读 Python PEP 257 关于 Docstring 的规范。
简要总结一下 PEP 257 中必须掌握的规范:

 1. 无论是单行还是多行的 Docstring,一概使用三个双引号括起;
 2. 在 Docstring 内部,文字开始之前,以及文字结束之后,都不要有空行;
 3. 多行 Docstring,第一行是概要,随后空一行,再写其它部分;
 4. 完善的 Docstring,应该概括清楚以下内容:参数、返回值、可能触发的错误类型、可能的副作用,以及函数的使用限制等等;
 5. 每个参数的说明都使用单独的一行……

 Sphinx 版本的 Docstring 规范

Sphinx 可以从 .py 文件里提取所有 Docstring,而后生成完整的 Documentation。将来若是你写大型的项目,需要生成完善的文档的时候,你就会发现 Sphinx 是个 “救命” 的家伙,省时、省力、省心、省命……

 P2D6.保存到文件的函数(模块)

 保存到文件的函数

我们可以将以下内容保存到一个名为 mycode.py 的文件中 —— 这样可以被外部调用的 .py 文件,有个专门的称呼,模块(Module)—— 于是,它(任何一个.py 文件)也可以被称为模块

用的时候通过import来导入

 模块文件系统目录检索顺序

  先去看看内建模块里有没有你所指定的名称;
 
 如果没有,那么就按照 sys.path 所返回的目录列表顺序去找。

你可以通过以下代码查看你自己当前机器的 sys.path

import sys
sys.path

在 sys.path 所返回的目录列表中,你当前的工作目录排在第一位。

有时,你需要指定检索目录,因为你知道你要用的模块文件在什么位置,那么可以用 sys.path.append() 添加一个搜索位置:

import sys
sys.path.append("/My/Path/To/Module/Directory")
import my_module

 引入指定模块中的特定函数

使用时用加模块名
import mycode
使用时不用加模块名
from mycode import * 
from mycode import is_prime

如果我们想要导入 foo 这个目录中的 bar.py 这个模块文件,那么,可以这么写:
import foo.bar 或者 from foo import bar

 引入并使用别名

from mycode import is_prime as isp
isp(3)

甚至干脆给整个模块取个化名:

import mycode as m
m.is_prime(3)
m.say_hi('mike', 'zoe')

dir() 函数
你的函数,保存在模块里之后,这个函数的用户(当然也包括你),可以用 dir() 函数查看模块中可触达的变量名称和函数名称,返回一个list

 P2D7.测试驱动的开发

在写程序的过程中,为别人(和将来的自己)写注释、写 Docstring;在写程序的过程中,为了保障程序的结果全面正确而写测试;或者干脆在最初写的时候就考虑到各种意外所以使用试错语句块 —— 这些明明是天经地义的事情,却是绝大多数人不做的…… 因为感觉有点麻烦。
这里是 聪明反被聪明误 的最好示例长期堆积的地方。很多人真的是因为自己很聪明,所以才觉得 “没必要麻烦”
但是,随着时间的推移,随着工程量的放大,到最后,那些 “聪明人” 都被自己坑死了 —— 聪明本身搞不定工程,能搞定工程的是智慧

 P2D8.可执行的 Python 文件

当一个模块(其实就是存有 Python 代码的 .py 文件,例如:mycode.py)被 import 语句导入的时候,这个模块的 __name__ 就是模块名(例如:'mycode')。

而当一个模块被命令行运行的时候,这个模块的 __name__ 就被 Python 解释器设定为 '__main__'

if __name__ == '__main__':
    main()

这么做的结果是:

 1. 当 Python 文件被当作模块,被 import 语句导入时,if 判断失败,main() 函数不被执行;
 2. 当 Python 文件被 python -m 或python xx.py运行的时候,if 判断成功,main() 函数才被执行。

 P2E.刻意思考

随着时间的推移,你会体会到它的威力:

 刻意思考哪儿需要刻意练习

只不过是一句话而已,却因知道或不知道,竟然会逐渐形成天壤之别的差异,也是神奇。
刻意思考,就是所谓的琢磨。琢磨这事,一旦开始就简单得要死,可无从下手的时候就神秘无比。让我们再看一个 “刻意思考” —— 即,琢磨 —— 的应用领域:

 这东西能用在哪儿呢?

找活干,是应用所学的最有效方式,有活干,所以就有问题需要解决,所以就有机会反复攻关,在这个过程中,以用带练……
所以,很多人在很多事上都想反了。
人们常常取笑那些呼哧呼哧干活的人,笑着说,“能者多劳”,觉得他们有点傻。
这话真的没错。但这么说更准:劳者多能 —— 你看,都想反了吧?

到最后,一切自学能力差的人,外部的表现都差不多,都起码包括这么一条:眼里没活。他们也不喜欢干活,甚至也没想过,玩乐也是干活(每次逢年过节玩得累死那种)—— 从消耗或者成本的角度来看根本没啥区别 —— 只不过那些通常都是没有产出的活而已

再高阶一点的刻意思考(琢磨),无非是在 “这东西能用在哪儿呢?” 这句话里加上一个字而已:

 这东西还能用在哪儿呢?

我觉得这个问题对思维训练的帮助非常深刻 —— 别看只是多了一个字而已。

当我读到在编程的过程中有很多的 “约定” 的时候,就琢磨着:

  哦,原来约定如此重要……
 
 哦,原来竟然有那么多人不重视约定……
 * 哦,原来就应该直接过滤掉那些不遵守约定的人……
 —— 那这个原理(东西)还能用在哪儿呢?
 —— 哦,在生活中也一样,遇到不遵守约定的人或事,直接过滤,不要浪费自己的生命……

学编程真的很有意思,因为这个领域是世界上最聪明的人群之一开辟出来并不断共同努力着发展的,所以,在这个世界里有很多思考方式,琢磨方式,甚至可以干脆称为 “做事哲学” 的东西,可以普遍应用在其它领域,甚至其它任何领域。
比如,在开发方法论中,有一个叫做 MoSCoW Method 的东西,1994 年由 Clegg Dai 在《Case Method Fast-Track: A RAD Approach》一书中提出的 —— 两个 o 字母放在那里,是为了能够把这个缩写读出来,发音跟莫斯科一样。

简单说,就是,凡事都可以分为:

  Must have
 
 Should have
  Could have
 
 Won't have

于是,在开发的时候,把所谓的需求打上这 4 个标签中的某一个,以此分类,就很容易剔除掉那些实际上做了还不如不做的功能……

 P3A.战胜难点

无论学什么,都有难点。所谓的 “学习曲线陡峭”,无非就是难点靠前、难点很多、难点貌似很难而已。
然而,相信我,所有的难点,事实上都可以被拆解成更小的单元,而后在逐一突破的时候,就没那么难了。逐一突破全部完成之后,再拼起来重新审视的时候就会发现那所谓的难常常只不过是错觉、幻觉而已 —— 我把它称为困难幻觉
把一切都当作手艺看的好处之一就是心态平和,因为你知道那不靠天分和智商,它靠的是另外几件事:不混时间,刻意思考,以及刻意练习 —— 其实吧,老祖宗早就有总结:

 天下无难事,只怕有心人……

大家都是人,咋可能没 “心” 呢?
想成为有心人,其实无非就是学会拆解之后逐一突破,就这么简单。

 P3B1.类 —— 面向对象编程

现在,OOP 的支持者与反对者在数量上肯定不是一个等级,绝大多数人支持 OOP 这种编程范式。
但是,从另外一个角度,反对 OOP 的人群中,牛人比例更高 —— 这也是个看起来颇为吊诡的事实。

 P3B2.类 —— Python 的实现

 P3B3.函数工具

这一章要讲的是迭代器、生成器和装饰器,这些都是函数工具。有人把它们称为 DIG(Decorator,Iterator,Generator)

 迭代器

i = iter("Python")
next(i)
next(i)
next(i)
next(i)
next(i)
next(i)
# next(i) 前面已经到 'n' 了,再调用就会有 StopIteration 错误提示。
class Counter(object):
    def __init__(self, start, stop):
        self.current = start
        self.stop = stop
    def __iter__(self):
        return self
    def __next__(self):
        if self.current > self.stop:
            raise StopIteration
        else:
            c = self.current
            self.current += 1
        return c


c = Counter(11, 20)
next(c)
next(c)
next(c)
for c in Counter(101, 105):
    print(c, end=', ')
type(Counter)

 生成器

生成器函数被 next() 调用后,执行到 yield 生成一个值返回(然后继续执行 next() 外部剩余的语句);下次再被 next() 调用的时候,从上次生成返回值的 yield 语句处继续执行

def counter(start, stop):
    while start <= stop:
        yield start
        start += 1
for i in counter(101, 105):
    print(i)

 生成器表达式

even = (e for e in range(10) if not e % 2)
print(even)
for e in even:
    print(e)

注意
仔细看 even = (e for e in range(10) if not e % 2) 中最外面那层括号,用了圆括号,even 就是用生成器创造的迭代器(Iterator),若是用了方括号,那就是用生成器创造的列表(List)—— 当然用花括号 {} 生成的就是集合(Set)……

 装饰器(Decorator)

Decorator 最常用的场景是什么呢?最常用的场景就是用来改变其它函数的行为
这是关键:

 函数本身也是对象(即,Python 定义的某个 Class 的一个 Instance)。

def a_decorator(func):
    def wrapper():
        print('We can do sth. before a func is called...')
        func()
        print('... and we can do sth. after it is called...')
    return wrapper()


def a_func():
    print("Hi, I'm a_func!")
  
a_func()
a_decorator(a_func)

通过装饰器操作符@a_decorator来装饰一个函数

def a_decorator(func):
    def wrapper():
        print('We can do sth. before calling a_func...')
        func()
        print('... and we can do sth. after it was called...')
    return wrapper


@a_decorator
def a_func():
    print("Hi, I'm a_func!")
  
a_func()
@a_decorator
def a_func():
    ...

# 等价于
def a_func():
    ...
a_func = a_decorator(a_func)

 P3B5.BNF 以及 EBNF

Backus-Naur Form(BNF,巴科斯-诺尔范式)和 Extended Backus-Naur Form(EBNF)
其实吧,真的不难的 —— 它就是语法描述的方法。描述语法格式的。

在自学这件事上,失败者的死法看起来千变万化,但其实都是一样的…… 只不过是因为怕麻烦或者基础知识不够而不去读最重要的文档

 P3C.拆解

在学习编程的过程中,你会不由自主地学会一个重要技能:拆解(任务分解)
这么简单的两个字,在人生中的作用重大到不可想像…… 而且它也的确是自学能力中最重要的底层能力之一
话说回来,自学的一个重要技巧就是,

 把那些很难的任务无限拆分 —— 直至每个子任务都很小,小到都可操作为止。
很多人最终自学失败,要么是不懂拆分任务,要么就仅仅是怕麻烦而已 —— 还是那句话,人活着就挺麻烦的……

 P3D.刚需幻觉

不要因为不是刚需就没有学习的动力了
“刚需幻觉” 的根源在于:你不会的东西,对你来说感觉上就不是刚需

 P3E.全面 —— 自学的境界

为了真正做到刻意练习,更重要的是需要不断地进行刻意思考 —— 刻意思考自己究竟应该在哪些地方必须刻意练习?
之前也说过,人和人非常不同,于是,需要刻意练习的地方也各不相同。
不过,倒是有一个方面,所有的自学者都必须刻意练习 —— 这是谁都逃不过的地方: 全面

那些 “貌似一出手就已然是高手” 的人就是在这一方面超越了绝大多数人 —— 在每个层面上,他们都学习得更全面,练习得更全面,使用得更全面,在使用此技能去创造的时候,思考得也就自然更为全面。于是,就产生了 “全面碾压” 的效果。

提高对所学知识技能的 “全面程度”,有个最狠的方法 —— 再次说出来不惊人,但实际效果惊到爆:

 教是最好的学习方法。

 P3F.自学者的社交

有一次朋友跟我聊起他苦于没办法培养自己孩子的正经兴趣爱好…… 我说,其实很简单,只不过是你方法错了。你不用告诉孩子 “应该学什么,应该对什么感兴趣”,而是,想尽一切办法让孩子见识到拥有那个技能的,令他产生羡慕情绪的人 —— 只要孩子羡慕那个人,他就自然而然地有 “我也想这样” 的想法,到最后,谁都拦不住。这就是镜像神经元的力量。进而,所谓的社交,还真不一定是非要跟人说话、聊天…… 见识到,也是社交的最主要组成部分。

我个人最看重的个人品质之一,就是有没有像样的作品

很少有人有像样的作品。人群中只有少数人最终能拿出完整的作品 —— 人与人之间的差异是如此之大,乃至于少数人有作品,更少数人有好的作品,只极少数极少数人才可能做出传世的作品;而与此同时,绝大多数人(万分之九千九百九十九的人)一辈子都没有像样的作品,他们连一篇作文都写不明白。于是,与有像样作品的人打交道,总是非常值得。
我甚至经常建议我的合伙人们,在招人的时候,把这一点当作最靠谱的判断方式。少废话,少吹牛逼,给我看看你的作品。这个原则可以一下子过滤掉所有的不合格者。另外一个很自然的现象是,如果一个人能做出像样的东西来,那么他身边的聪明人密度无论如何都会比其他人的高出很多。

所以,无论学什么,都要想尽一切办法尽快做出自己的作品。做一个产品出来的过程中,会磨练另外一项自学者不可或缺的能力和素质:

 完整

与之前提到的另外一项加起来,就构成了自学者的最基本素养:

  学就学得全面
 
 做就做得完整

无论多小的作品,都会让创作者感受到 “单一技能的必然无效性” —— 你试试就知道了。哪怕你想做个静态网站,你都会发现,仅仅学会 html/css 是不够的,因为部署到远端服务器上的时候,你无论如何都得学学 Linux 基本操作…… 而已然具备了自学者基本素养的你,自然会想办法 “全面掌握”,而不是糊弄一下而已。

手艺人不怕做的事小。而且,“小” 无所谓,完整 才是关键。

有作品和没作品的人理解能力也不一样。做过作品的人,看到类似 MoSCoW Method 的做事原则,瞬间就能有所感悟,而没有作品的人,却不见得有一样的感受。

 顺带给你看个 Wikipedia 上的链接列表,在编程领域里,有无数可以借鉴到生活中的哲学、方法论:
 - If it ain't broke, don't fix it
 - KISS principle
 - Don't repeat yourself
 - Feature creep
 - List of software development philosophies
 - Minimum viable product
 - MoSCoW method
 - Overengineering
 - Worse is better
 - S.O.L.I.D.
 - Unix philosophy

 P3G.the-golden-age-and-google(这是自学者的黄金时代)

 P3H.避免注意力漂移

注意力漂移,是我杜撰的一个词,用来作为 注意力集中 的反义词 —— 因为更多的时候,我们并不是 “注意力不集中”,而是…… 而是更令人恼火的一个现象:

 “注意力所集中的焦点总是不断被自己偷偷换掉……”

比如,你本来只不过就想着去 Google 一个编程错误信息的解读,结果不知道怎么就 “注意到” 了另外一个东西,比如,“某编辑器的皮肤”,然后你就 “顺手” 把它下载下来,然后 “很自然地顺手把它装上”,而后又看了看,觉得有点必要于是 “顺手做了点定制”…… 然后欣赏了一会儿,并自我得意一番之后 “突然发现” 自己还没有解决两小时之前要解决的问题!

说这种现象 “令人恼火”,是因为那注意力所集中的焦点,是被自己偷偷换掉的!

好奇心越重的人,越是容易被注意力漂移所拖累。

 注意力漂移不是能杜绝的现象,但必须在关键时刻有所应对……

我买笔记本,不是为了记笔记的,因为记笔记这个东西,实在是在电脑上做更方便,许多年前开始就是如此了。我的笔记本主要用来做一件事:
 罗列整理那些为了做到 “全面完整” 而必须优先做的事。
用列表也好、或者用图表也罢,反正都是要不断整理修订的,而它的存在,给了我一个优先级:
 除了这上面罗列的这些东西之外,在当前时间段,别的都不如它们重要。
一旦发现自己的注意力没有集中在这上面的关键之时,一旦发现自己的注意力已经漂移到其它当前并不重要的事项上,就马上纠正。

 Q.如何成为优秀沟通者

一般认为,“手艺人” 的普遍特征之一就是缺乏沟通能力,或者沟通能力差 —— 也许是因为平时把所有的时间精力都投入到磨练手艺上去了罢。
但这肯定不是最主要的原因。你看手艺不怎么样的人沟通能力更差;手艺顶级的人却常常反过来沟通能力很强很强…… 为什么呢?
所以,最核心的理由,应该是一个人最基本的选择而已:

 看一个人是否重视沟通能力。

因为若是一个人重视沟通能力,那么,他就自然而然地会想办法去进行刻意练习。如果他本人并不重视沟通能力,那么,自然就没有任何时间精力投入在这方面,结果就非常自然而然了。

对沟通能力进行 “刻意练习” 的最佳方式是什么呢?其实还是你已经知道的

 教是最好的学习方法
讲课、写教程,甚至写书 —— 这是最高效的提升沟通能力的刻意练习手段。
讲演能力、写作能力,其实同样也是手艺而已,但它们也确实是很必要的手艺。尤其是,具备这两项手艺的人,在现在这样的社会里收入一定不差,不信你就观察一下身边的世界、你的眼界可以触达的人群。

 入门

 内容第一

无论是平日里讲话、还是台上讲课,抑或是写篇文章、写本书,永远都是内容第一,至于形式,并非不重要,但绝对不能喧宾夺主。
通常,我们用 “干货” 来描述内容的重要性。第一步就是准备干货,至于修辞啊、笑点啊、酷炫幻灯片啊等等等等,都必须是次要的,否则就是喧宾夺主。干货不够好,其它的做得越多、越好,最终越是容易露怯 —— 这很可怕。

 内容质量

内容第一,就决定了另外一个事实:

 不要讲或写你并不擅长的事。
换句话说,不要分享你做得不够好、做得不够精的手艺。讲课也好、写书也罢,都是分享。分享的意思是说,你有别人想要的东西 —— 别人想要的,就是他们学不好、做不好的东西…… 若是你自己手艺不强,手艺不精,其实就没什么可分享的,就算你想 “分享”,别人也不要。
你值得讲,别人值得听的,一定是你做得比别人更好的东西,就这么简单。
一旦你确定自己有值得讲、人家值得听的东西,那么,内容质量的第一要素已经完成了,接下来要注意哪些呢?只需要关注最重要的三个方面就可以了:
 - 重点突出
 - 例证生动
 - 消除歧义

 内容组织

只有一个重点的时候,其实并不需要组织;但若是有一个以上的重点,那么这些重点之间会产生逻辑关系:

 - 并列
 - 递进
 - 转折

 进阶

当入门的手段都已经熟练了,就可以做很多所谓 “锦上添花” 的事情。锦上添花据说有很多种手段,比如,制造笑点啊,使用炫酷的幻灯片啊等等…… 但我只想给你讲一个学会了就够用,却也是最简单、最直接,然而又最有效的手段:

 输送价值观

 高级

 R.自学的终点

磨练自学手艺的你,早晚会遇到这种情况:

 必须学会一个没人教、没人带,甚至没有书可参考的技能。

然而,仅仅 “谁能持续研究谁就更可能先成为专家” 这一条,其实并不够完成 “学会一个没人教、没人带,甚至没有书可参考的技能”。

这么多年来,我能够 “学会一些没人教、没人带,甚至没有书可参考的技能”(比如赚钱这事就是如此),更多的时候仰仗的是一个我已经告诉过你的 “秘密”…… 也许你想不起来了,但我一说你就能 “发现” 其实你真的已经听我说过

 刻意思考:这东西我能用在哪儿呢?