基础
环境
- REPL
- ipython
- emacs
实践: hello, world
类型
- 字符变量
- 数字变量
- 布尔变量
- 序列容器
- 非序列容器
- 第一类函数对象(first class function)
结构
- 选择结构
- 循环结构
- 迭代结构
- 块结构
实践: Guess the number/with feedback
函数
- 普通函数
- 匿名函数
- 变长参数
- 参数默认值
- 生成器
实践: fibonacci/memorized
小技巧
- 列表推导式
- 闭包
- 装饰器
- map/reduce
作用域规则(scoping)
- LGB
- LEGB
- unbound
实践: 24 game
面对对象
类
- 成员变量
- 成员函数
- 可见性
- 继承
- property
- 多继承
- plugin
实践:
- balanced tree/two dimension
- balanced tree/three dimension
异常
- 执行转移
- 系统异常和程序异常
实践: 异常重定向
模块
- 路径和导入规则
实践: dynamic plugin modules
闭包和对象类的联系
class Out(object):
def __init__(self, a, b, c):
self.a, self.b, self.c = a, b, c
def __call__(self):
use self.a, self.b, self.c
return xxx
装饰器注册
class Reg(object):
def __init__(self):
d = {}
def register(self, path):
def inner(f):
self.d[path] = f
return f
return inner
reg = Reg()
@reg.register('/abc/')
def action1():
pass
反模式
函数默认值
函数的默认值,在同一个函数内是同一个。不要用可变值作为默认值。
def sumobj(l=None):
if l is None: l = []
return reduce(lambda x, y: x+y, l)
局部变量定义
在内层中后定义的对象会导致先使用的对象出错,尤其在全局有同名变量时,这容易产生混淆。
a = 1
def func():
print a
a = 2
更具有迷惑性的例子:
a = 1
def func():
if True: print a
else: a = 2
battery inside
内置模块
- os
- sys
- re
- path
- datetime
- logging
- math
- random
- shutil
- hashlib
- getopt
- collections
- ConfigParser
实践: getopt
文件系统
- 读写
- 管理
- 对象序列化
- json
- pickle
- marshal
- 不同格式读写
- csv
- zipfile
- tarfile
实践: find duplicate files
第三方模块
- requests
- beautifulsoap
高级特性
测试
- unittest
示例:
- hashlib
调试
- pdb
块
- 使用
- 定义
流
- 每次取得一个元素
- 不可跳过下一个元素取得后续元素
- 不可回朔前一个元素
过滤和映射
列表推导 [map(i) for i in list if filter(i)]
-
循环
rslt = []
for i in list:
if filter(i): continue
i = map(i)
rslt.append(i) -
函数式
def proc(i):
do i
def isi(i):
test i
map(proc, filter(isi, list))
注意itertools的imap和ifilter才是生成器模式,2.7中的map和filter都是直接把结果list生成出来的。 -
dict过滤
dict([(mapk(k, v), mapv(k, v)) for k, v in dict.iteritems() if filter(k, v)])
dict推导式(python3后有效) {k: v for k, v in dict.iteritems()}
列表推导和循环隐含假定不可并发,函数式隐含假定可并发。
过滤装饰器
结合生成器流和过滤的手法。
def filterxxx(list):
for i in list:
if filter(i): continue
i = map(i)
yield i
for i in filterxxx(source):
do i
优点是很容易写出多层过滤正交。
实践: find duplicate files/insertable functions
网络
底层协议
- tcp协议栈
- 服务器端
- 客户端
- udp协议栈
实践: ping-echo server(tcp and udp mode)
应用层协议
- urllib
- smtplib
代码风格
过程式风格
- 一行语句完成一项简单工作
- 自行显式管理中间变量
- 偏好迭代而非递归
- 基本控制结构为分支和循环
面对对象风格
- 复杂的对象和继承结构
- 对象拥有众多方法
- 对外暴露一致性抽象接口
要点
- 不要在基类中声明一遍未实现
- 可以放弃显式基类,改为约定基类(duck typing)
- 多接口可以用maxin模式实现
- 少用super
函数式风格
- 大量使用高阶函数和第一类函数对象
- 在小幅使用闭包替代微型类
- 一行流,代码经常写成lisp缩进风格
- 经常使用“无副作用函数”
- 偏好递归而非迭代
- 基本控制结构为函数构造形态
要点
- 不要过度迷信函数对象,尤其是在python没有尾递归优化,函数调用开销又很高的情况下。
- 注意什么时候用闭包,什么时候用类。
- lisp风格的一行流不利于调试,python没有调用树中间显示,因此在这一行上报出的错误可能是在任何一个调用中,需要自行判断
- lambda可以用于lazy evaluation,很有用
结合多种风格
- 在面对对象风格的具体函数实现中,可能出现局部的过程风格和函数风格。
- 对象可能大量产生一类函数对象,用于高阶函数中。
- 完成目标的风格是最好的风格
哲学
duck typing
- 没有基类,却行为一致,就可以互换使用
- 不要将静态语言思路用于动态语言,尤其是多重继承和父类的空函数
- 正确的传递和处理参数是程序员的责任,不是IDE的
POLA
the principle of least astonishment
- 函数返回值是否有多种可能,需要根据情况来判断?
- 函数返回值确定,但是值的类型是否多变?
错误处理
- 函数不可能又返回值又返回错误,使用异常处理错误。
- 尽早出错。不要做输入检测,不要写保护性代码,不要容错,不要处理异常。
- 不要捕获额外的错误,尤其禁止捕获Exception
- 尽量使用python现有的异常,例如ValueError。除非有必要做出区分。
- Errors should never pass silently, Unless explicitly silenced.