《the self-taught programmer》阅读笔记
在李笑来老师的微博里知道《the self-taught programmer》这本书,当前还是在美亚上买的。整个阅读的过程也是断断续续的,经过了多次“从入门到放弃”;有时是读完了,也不知道到底自己算入门了没有;有时是读了后面的忘了前面的知识点,总之是没有多少沉淀在心里。
重新再过一遍,把知识点再这里提下,这里提的知识点更多的是自己的知识盲点。
本书一共分为五个部分:
Part I:Introduction to Programming
Part II: Introduction to Object-Oriented Programming
Part III: Introduction to Programming Tools
Part IV: Introduction to Computer Science
Part V : Landing a Job
Part I:Introduction to Programming
注释:#
\ slash:可换行,原则上一条语句一行
一般缩进:四个空格
Data Type:identity(location in memory),data type(str int float bool nonetype..),value
变量命名规则:以数字、字母、下划线组成,不能有空格,数字不能做开头,常见的有驼峰法和大小写法
错误类型:syntax error 和exception
运算符:算计--比较--逻辑 ,记得有优先级
control structure--》conditional statements
函数名命名时最好不要含大写字母,可以下划线
Built-in Functions: print len str int flaot input...
???except 后面的错误类型有哪些?ZeroDivisionError,ValueError
docstring 书写要全面一点
def add(x,y):
"""
Returns x+y 干什么的
:param x: int
:param y: int
returns int sum of x and y.
"""
returns x+y
scope:global 和??
Containers:list ,tuple ,dictionary
image.pngContainers | iterable | mutable |
---|---|---|
List | √ | √ |
tuple | √ | × |
dictionary | √ | √ |
string: iterable ,immutable.
+号 、 * 、 upper()、lower()、capitalize()、‘’xxx {}".format("yyy")、split(‘’x') x为分隔符、join() 'x'.join('string')、strip()、sring.find('x')、index()、replace()、in、\转移字符 \n \t '、slice--iterable[index0:index1]
LOOP
for-loop | while-loop |
---|---|
1.for i in [iterable] 2.for i,item in enumerate([iterable]) 3.for i in range(m,n) | while [expression]: |
break--退出循环;continue--退出本次循环进入下一次循环;iterable:string ,list,tuple,dictionary |
built-in module | other module |
---|---|
math、random、keyword、statistics ... | if name =="main": print("hello") 开头加这几行会使得导入模块时不会直接显示Print的结果 |
- Files
利用os module 构建文件路径,来适应不同的操作系统。
import os
os.path.join('users','bob','st.tx')
open一个文件,需要一个close来关闭文件;使用with-statement python会自动关闭文件
with open("st.txt", "w) as f:
f.write("hello")
II Introduction to Object-Oriented Programming
- programming paradigms :
1.过程式编程(procedural programming):一系列步骤来解决问题,每步都会改变程序的状态。适合简短的程序编程。由于程序的状态都保存在全局变量中,随着程序规模扩大, 可能会在多个函数中使用全局变量,很难记录都有哪些地方对一个全局变量进行了 修改。
2.函数式编程(functional programming):消除全局状态,解决了过程式编程中出现的问题,不使用或不改变全局状态的函数, 唯一使用的状态就是传给函数的参数。一个函数的结果通常被继续传给另一个函数。 因此,这些程序员通过函数之间传递状态,避免了全局状态的问题,也因此消除了由此 带来的副作用和其他问题。
3.面向对象(object-oriented)编程范式也是通过消除全局状态来解决过程式编程引发 的问题,但并不是用函数,而是用对象来保存状态。
根据惯例,Python 中的类名都是以大写字母开头,且采用驼峰命名法,即如果类名由多 个单词组成,每个单词的第一个字母都应该大写,如 LikeThis,而不是用下划线分隔(函数的命令惯例)。
面向对象编程有四大概念:封装、抽象、多态和继承。
encapsulation:在面向对象编程中,对象将变量 (状态)和方法(用来改变状态或执行涉及状态的计算)集中在一个地方— 即对象本身;隐藏类的内部数据,以避免客户端(client)代码(即 类外部的代码)直接进行访问。Python 中没有私有变量,所有的变量都是可以公开访问的。Python 通过另一种方法 解决了私有变量应对的问题:使用命名约定,变量名前有下划线。
抽象(abstraction)指的是“剥离事物的诸多特征,使其只保留最基本的特质”的过 程。在面向对象编程中,使用类进行对象建模时就会用到抽象的技巧。
多态(polymorphism)指的是“为不同的基础形态(数据类型)提供相关接口的能力”。接口,指的是函数或方法。
继承(inheritance)另一个类那里继承方法和 变量。被继承的类,称为父类(parent class);继承的类则被称为子类(child class)。
组合 (composition)将一个对象作为变量保存在另一个对象中,可以模拟“拥 有”关系。例如,可使用组合来表达狗和其主人之间的关系(狗有主人)。
类变量:类中但在init方法之外中定义的。访问方式与实例变量(变量名前面加 self.)的访问方式相同。 类变量可以在不使用全局变量的情况下,在类的所有实例之间共享数据。
实例变量 类中init中方法中定义的
魔法方法
III: Introduction to Programming Tools
Bash command-line interface
一些命令:echo同print、history查看最近的命令、pwd查看当前目录、/表示根目录,如果不以/开头,则说明使用了相对路径、cd /到根目录、ls显示当前目录中的文件、mkdir创建目录、cd ~到home路径、cd ..返回上层目录、rmdir 删除文件、whoami显示当前用户
命令支持一个叫旗标(flag)的概念,可以改变命令的执行方式。旗标对于命令来说, 是一些值为 True 或 False 的执行选项。一个命令的所有旗标默认置为 False。
操作系统和很多程序都会将数据保存在隐藏文件中。隐藏文件指的是默认不会展示 给用户的文件,因为修改隐藏文件会影响依赖这些文件的程序。隐藏文件的名称以英文 句点开头,如.hidden。在 ls 命令后加上旗标-a(表示所有文件),即可查看隐藏文 件。touch 命令支持从命令行新建文件。
在类 UNIX 操作性系统中,竖直线“|”被称为管道(pipe)。可使用管道将一个命 令的输出,传入另一个命令作为输入。例如,可使用 ls 命令的输出,
环境变量(environment variable)是保存在操作系统中的变量,程序可通过这些变量 获取当前运行环境的相关数据,如运行程序的计算机的名称,或运行程序的用户的名称。 使用语法 export[变量名]=[变量值],即可在 Bash 中新建一个环境变量。如需在 Bash 中引用环境变量,必须在其名称前加一个美元符号。示例如下:
export x=100
echo $x
将环境变量添加到类 UNIX 操作系统使用的一个隐藏文件中,可使得环境变量持久 存在。该隐藏文件位于 home 目录下,名为.profile。使用图形用户界面前往 home 目录。可在命令行输入 pwd ~,找到 home 目录的绝对路径。然后,使用文本编辑器创 建一个名为.profile 的文件,在第一行输入 export x=100 并保存文件。之后,退 出并重新打开 Bash,这时就能够打印环境变量 x 了。
可在命令前加上 sudo(superuser do 的简称)。sudo 可在不影响操作系统安全性 的前提下,让我们以根用户的身份执行命令
正则表达式(regular expression):定义搜索模式的 一组字符串。
grep 命令接受两个参数:一个正则表达式和检索正则表达式中定义模式的文件路 径。
grep xxx zex.txt
grep -i xxx zex.txt
加上旗标-i 来忽略大小写;添加旗标-o,确保只打印与传入的模式参数相匹配的文本:
通过内置模块 re 在 Python 中使用正则表达式。re 模块提供了一个叫 findall 的方法,将正则表达式和目标文本作为参数传入,该方法将以列表形式返回文本中与正 则表达式匹配的所有元素.
import re
l = "Beautiful is better than ugly."
matches = re.findall('Beautiful',l,re.IGNORECASE)
print(matches)
使用补字符号 ^ 创建一个正则表达式,表示只有模 式位于行的起始位置时才匹配成功;使用美元符号$来匹配结尾指定模式的文本行;在 Python 中使用补字符 ^ 的示例(必须传入 re.MULITILINE 作为 findall
的第 3 个参数,才能在多行文本中找到所有匹配的内容):
在正则表达式中加入[abc],则可匹配 a、b 或 c;可使用[[:digit:]]匹配字符串中的数字:在Python 中使用\d匹配数字
星号符*可让正则表达式支持匹配重复字符。加上星号符之后,星号前面的元素可匹 配零或多次
在正则表达式中,句号可匹配任意字符。如果在句号后加一个星号,这将让正则表 达式匹配任意字符零或多次。也可使用句号加星号,来匹配两个字符之间的所有内容。正则表达式.*可匹配两个下划线之间(包括下划线)的所有内容。星号是贪 婪匹配(greedy),意味着会尽可能多地匹配文本。如果不想一直贪婪匹配,可以在星号后面加个问号,使得正则表达式变成非贪婪模 式(non-greedy)。一个非贪婪的正则表达式会尽可能少地进行匹配。grep 并不支持非贪婪匹配,但是在 Python 中可以实现.
可以在正则表达式中对字符进行转义(忽略字符的意义,直接进行匹配)。在正 则表达式中的字符前加上一个反斜杠\即可进行转义
$ echo I love $ | grep \\$
package manager pip install module_name(==版本号);pip freeze查看已安装模块;删除模块pip uninstall module_name.(删除是后面有个点的)
Version Control
- 在github上创建一个repository
- git clone [repository_name]
- 主要2件事是 pushing (将本地所做的修改更新至中央代码仓库)和 pulling。推送修改到中央代码仓库共分 3 步。1.暂存(stage)文件,告诉 Git 希望将哪 个修改过的文件推送到中央代码仓库。命令 git status 可以显示项目之于代码仓库的当前状态,方便我们决定暂存哪些 文件。该命令会把本地代码仓库与中央代码仓库中存在差异的文件打印出来。取消文件暂存后,文件以红色字体显示。暂存的文件显示为绿色。要确保位于 仓库 目录,然 后输入命令 git status。使用命令 git add[文件名]即可暂存文件;现在通过命令 git status 确认已经暂存了该文件,会变为绿色 ,提交文件,即 命令 Git 记录本地代码仓库所做的修改。2.可使用语法 git commit -m [信息]提交 文件。该命令将创建一次提交(commit):Git 保存的一个项目代码版本。3.可通过命令 git push origin master,将本地的修改推送到中央代码库:
pulling前往中央代码仓库,点击按钮 Create new file,创建一个名为 new.py 的文件,然后 点击按钮 Commit new file 提交该文件。这个文件目前没有在本地代码仓库中,因此本地 代码仓库落后于中央代码仓库的版本。我们可以使用命令 git pull origin master 更新本地代码仓库:
命令 git remote -v(-v 是一个常用的旗标,用来打印详细信息)可打印本地代 码仓库推送和拉取代码的目标 URL 链接。
使用语法 git reset[文件路径]即可取消暂存。
可使用命令 git log 查看项目的提交历史,该命令会打印出所有做过的提交
命令 git diff (git diff xxx.py )可实现本地代码仓库与中央代码仓库之间文件的差别对比
IV: Introduction to Computer Science
Data Structures
- Stack :LIFO
class Stack:
def __init__(self):
self.items = []
def is_empty(self):
return self.items == []
def push(self, item):
self.items.append(item)
def pop(self):
return self.items.pop()
def peek(self):
last = len(self.items) - 1
return self.items[last]
def size(self):
return len(self.items)
==================
stack = Stack()
for c in "Hello":
stack.push(c)
reverse = ""
for i in range(len(stack.items)):
reverse += stack.pop()
print(reverse)
- Queue:FIFO
Algorithms
算法(algorithm)是解决问题的一系列步骤.
搜索算法(search algorithm)用来在列表等数据结构中查找信息。顺序搜索(sequential search)是一种简单的搜索算法,依次检查数据结构中的每个元素,判断其是否与查找的 元素相匹配。
def ss(number_list, n):
x = False
for i in number_list:
if i == n:
x = True
break
return x
========================
number_list = range(100)
n = 100
print(ss(number_list, n))
回文词(palindrome)指的是逆序和正序拼写得出的单词都相同的词。
def palindrome(word):
word = word.lower()
return word == word[::-1]
=============================
print(palindrome("non"))
变位词(anagram)是通过重新组合另一个单词的字母所组成的单词。
def anagram(w1, w2):
w1 = w1.lower()
w2 = w2.lower()
return sorted(w1) == sorted(w2)
===============================
print(anagram("god","dog"))
计算字母频数
def count_characters(string):
count_dict = {}
for c in string:
if c in count_dict:
count_dict[c] += 1
else:
count_dict[c] = 1
print(count_dict)
==================
count_characters("I am a hero")
**递归式算法(recursive algorithm) **则是通过调用自身的函数来实现。任何可以迭代式解决的问题,都可以递归式地解决; 但是,有时候递归算法是更加优雅的解决方案。
1.递归算法必须有终止条件。
2.递归算法必须改变自己的状态,不断靠近终止条件。
3.递归算法必须递归地不断调用自己。
def bottles_of_beer(bob):
""" Prints 99 Bottle
of Beer on the
Wall lyrics.
:param bob: Must
be a positive
integer.
"""
if bob < 1:
print("""No more
bottles
of beer
on the wall.
No more
bottles of
beer""")
return
tmp = bob
bob -= 1
print("""{} bottle of
beer on the
wall. {} bottles
of beer. Take one
down, pass it around, {} bottles
of beer on the wall.""".format(tmp,tmp,bob))
bottles_of_beer(bob)
============================
bottles_of_beer(99)
V : Landing a Job
几个普遍的编程原则
- 写代码是最后的手段.先在网上检索解决办法,只有在确定没人解决过该问题之后,才开始自己动手解决。
- 正交性(Orthogonality)。在设计优良的系 统中,数据库代码与用户界面之间是正交的;调整用户界面不会影响数据库,替换数据 库也不会改变用户界面。”实践中请牢记,“A 不应该影响 B”
- 每个数据都只应保存在一处
- 函数只做一件事
- 若耗费时间过长,你的做法很可能就是错的
- 第一次就要用最佳的方法完成
- 遵循惯例。PEP8 是一系 列编写 Python 代码的指南,强烈建议阅读,可前往 https://www.python.org/dev/peps/ pep-0008/查看。
- 使用强大的 IDE
- 记录日志,记录日志(logging)指的是在软件运行时记录数据的做法。我们可通过日志来协助 程序调试,更好地了解程序运行时的状态。Python 自带了一个 logging 日志模块,支持 在控制台或文件中记录日志。
10。 程序测试指的是检查程序是否“达到了设计和开发要求,对各类输入返回正确的结 果,功能执行耗时在可接受范围,可用性足够高,可在目标环境下安装和运行,并且实 现了相关利益方所期待的效果。可在网页 https://docs.python.org/3/library/unittest.html 学习如何使用 Python 自带的 unittest 模块。 - 代码审查。在代码审查(code review)时,同事会阅读你的代码并提供反馈。
- 安全。学习编程时我们也不会去考虑安全问题。但是,在实际工作中,我们需要 对自己代码的安全性负直接责任。非必要情况下, 务必不要在命令行使用 sudo 执行命令;总是假设用户的输入是恶意的;最小化你的攻击面积(attack surface),即黑客可 从程序中提取数据或攻击系统的相关区域。通过最小化攻击面积,可以减少程序出现漏 洞的可能性。最小化攻击面积的几种常见做法包括:避免保存敏感信息,赋予用户最低 的访问权限,尽可能少用第三方库(代码量越小、漏洞越少),剔除不再使用的功能代码(代码量越小、漏洞越少)等;但这还只是提升安全性的一小部分。我们应该试着从黑 客的角度进行思考。
更多学习资料
- 经典书籍。有一些编程书籍是必读书目。《程序员修炼之道》《设计模式》1《代码大全》《编译原理》,以及 MIT 出版社出版的《算法导论》均为程序员必读书目。另外,强烈推荐 一个免费的互动式算法入门教程,名为《Problem Solving with Data Structures and Algorithms》,这本书比《算法导论》更加容易理解。
2 在线课堂 http://theselftaughtprogrammer.io/ courses 网页中列出了值得推荐的课程。
3.骇客新闻(Hacker News)是技术孵化器Y Combinator推出的一个用户新闻分享平 台,网址为 https://news.ycombinator.com,能够帮助大家及时掌握最新的趋势和技术。
下一步你应该怎么做?要学习数据结构和算法,请前往 LeetCode 网站,进行算法练习,然后寻找更多的练习机会。
作者分享一 些有关如何持续提升程序员技能的思考。
- 找到导师
- 加深理解,编程领域中有一个叫“黑盒”的概念,指的是某个你在使用,但是并不了解其工作 原理的东西。刚开始编程时,对你来说一切都是黑盒。提升编程能力的一个最好的方式, 就是打开碰到的每个黑盒,努力掌握其原理。
- 尽可能多花时间阅读其他人的代码。
尼尔·科伊勒的《The Talent Code》提升了我的编程能力,因为他教会了我掌握任何一个技能所需要的方法论。时刻注意编程领域之外的动态,注重吸收那些有助于编程的知识。