读《Effective Python:编写高质量Python代码的59个有效方法》小记
写在前面
Python 很优美的语言,近几年迅速成为最流行的语言,为什么?
- 语言的全面性:啥都能干,数学计算,GUI开发,WEB开发(框架近百种),AI分析,数据量化分析、爬虫、文档处理等等;
- 易用性: 很多非IT的人群,学习该语言,入门简单,易于使用。毫不夸张的说:有时候,Python的一行代码可以抵得上C语言100行代码,效率上还相近,Why not 不用?
2010年,个人在IT公司,进驻华东某省银行分行进行中间业务平台建设,用的Python2.3 语言开发项目,当时纯粹作为应用,没有深入去思考该脚本语言的起始,如今从Python 3.6+ 入手,无论从风格,还是封装性,全面性都有本质的提升。
随着年龄增长,Python很显然让我有了抛弃C/C++ 、java语言的想法。尽管google公司依据python,开发了编译型的GO语言,但仅是在某些方面表现卓越,不如Python的通用性。
未来是脚本语言的天下,Python必然是这方面的王者。
# 任何部分的知识点 都应该遵循”WHY、WHAT、HOW、WHERE“去学习。 # WHY:为什么存在,即背景; # WHAT: 是什么,概念; # HOW: 怎么使用; # WHERE: 什么时候使用 或 在哪里需要使用。

Chapter 1: 用Pythonic 方式思考
1. Python式编程风格(Pythonic)
# 选定合适的python版本
# Python是解释型、强类型语言
>>> python --version
# 或
>>> import sys
>>> print(sys.version_info)
>>> print(sys.version)
# 变量 :驼峰或下划线单词间隔(推荐后一种)
# 常量 :约定俗成 全部大写 代表不修改,实际语言上是可以修改,Python中无C语言中的const 修饰符。 示例:BIRTH_OF_CHINA = 1949
# 注释: 出于阅读理解的需要,注释是个很好的习惯。
# 单行注释:#;多行注释 ‘’‘注释内容’‘’ 或 “”“注释的内容 ”“”
”“”
基础数据类型:是对现实信息的精准划分。数字、汉字、英文……;机器很傻 需要指定类型 告诉计算机 数据的类型。
整形:1, 10 等 加减乘除
字符串:单引号 和 双引号 等价;还有三引号 ’‘’ 用于换行的字符串
单引号 和 双引号 可以配合使用。
示例: age = ” I’am lei.wang “
布尔类型:True 或 False
查看变量类型 type(var)
“”“
2.遵循PEP8 风格(习惯很重要)
# PEP 全称为:Python Enhancement Proposal #8
# 即8号python增强提案
# Zen Of Python
# Python 之禅
# command line mode 模式
>>> import this
3. Python3与Python2的区别
- python3:bytes 表示二进制 ,str 表示unicode;
- python2:str表示二进制 ,unicode表示unicode;
- 转换utftobin 用encode(),解码用decode();
- 文件操作上 python3用utf8方式,所以在对二进制操作时候,要rb或wb模式;python2中默认用二进制操作文件,兼容上述表达。
4. 切片
在Python中,空字符串、空列表、零值都会被评估为False;
列表切割 会产生另一份全新列表,原列表引用不变;
当列表有起始索引,还有 步进 时候,应先做范围切割,再做步进;
对于 -1 步进 对字符串取反的技巧,只适应于 字节串 和 ASCII,Unicode不适合;
5. 推导式
# 1. 无参数映射 考虑 列表推导式
a = [1, 2, 3, 4, 5, 6]
squares = [x**2 for x in a]
print(squares)
>>>>>
[1, 4, 9, 16, 25, 36]
#内置map() 函数写法
squares = map(lambda x: x ** 2, a)
# 2. 涉及到原列表过滤时候,更方便
even_squares = [x ** 2 for x in a if x%2 == 0]
# 实现上述同样功能 需要map() 和filter() 函数使用
alt = map(lambda x: x**2, filter(lambda x: x%2 == 0,a))
assert even_squares == list(alt)
# 3. 字典dict() 和 集合set() 同样支持 推导式 comprehension
# 对应的范围符号要改为 ‘{ }’
# 4. 矩阵处理 双层循环支持
# 矩阵 即是包含列表的列表,即二维列表
matrix = [[1,2,3], [4,5,6], [7,8,9]]
flat = [x for row in matrix for x in row]
print(flat)
>>>>>
[1, 2, 3, 4, 5, 6 ,7, 8, 9]
# 矩阵每个元素处理,如平方
# 先由外面'[]'推导,在进入第二层'[]'
# 这样理解比较有条理性
squared = [[x**2 for x in row ] for row in matrix]
# 从矩阵中为3所整除的,且所在行元素之和大于等于10 单元格选择出来
filtered = [ [x for x in row if x % 3 == 0]
for row in matrix if sum(row) >= 10]
6. 生成器
# 生成器表达式(generator expression) 相比于列表推导式(comprehension) 内存使用上有效率
# 用生成器表达式改写 推导式,针对文件操作 大数据操作 采用生成器
# 用'()' 替代 '[]' 就变成 生成器,返回 迭代器(iterator)
it = (len(x) for x in open('/tmp/leige_file.txt'))
print(it)
>>>
<generator object <genexpr> at 0x101b81480>
print(next(it))
print(next(it))
>>>
100
57
# 生成器 组合使用 执行效率表现很好
roots = ((x,x ** 0.5) for x in it)
print(next(roots))
>>>
(15, 3.87298334)
7. enumerate() 与 range()
# range() 一般针对整数 序列进行迭代操作
# enumerate() 针对 字符串序列,需要自动生成索引下标,成对出现 使用
flavor_list = ['vanilla', 'chocolate', 'pecan', 'strawberry']
# 列表写法
for i in range(len(flavor_list)):
flavor = flavor_list[i]
print('%d:%s'%(i+1, flavor))
# enumerate()写法
for i,flavor in enumerate(flavor_list):
print('%d: %s' % (i+1,flavor))
#或 提供第二个参数,以指定开始计数时所用的值(默认为0)
for i,flavor in enumerate(flavor_list, 1):
print('%d: %s' % (i,flavor))
8. Zip()函数
# zip() 平行遍历2个迭代器
# 一般两个迭代器存在关联,等长关系,不等长 以最短提前终止
# 示例
names = ['Cecilia', 'Lise', 'Marie']
letters = [len(n) for n in names]
longest_name = None
max_letters = 0
for name,count in zip(names, letters):
if count > max_letters:
longest_name = name
max_letters = count
9. 异常模块组合
# try/except/else/finally
# finally 最后 必须执行的模块,常用来执行 清理收尾 或 关闭句柄
# exp
handle = open('/tmp/random_data.txt')
try:
data = handle.read()
finally:
handle.close()
# try except else
# try 无异常,执行else 这方面往往会产生误解
10. 函数与异常
尽量用异常来表示特殊情况,而不要返回None;
原因在于:None 和 0 以及 空字符串之类的值,在条件表达式里都会评估为False。
yield 和可变位置参数 star args
11. 关键字参数和动态参数
关键字参数:
- 所有的位置参数,都可以按关键字传递;
- 位置参数必须出现在关键字参数之前;
- 关键字参数提高可读性,也可以为函数定义提供默认值;
- 为函数扩充有效参数提供了有效方式;
- 关键字参数设置,关键字参数调用。
动态默认值参数:
参数的默认值,只会在程序加载模块并读到本函数的定义时评估一次。对于{}和[]等动态值,可能会导致奇怪的行为。
动态值作为参数,应该默认值是None。
# 程序执行日志示例 def log(msg, when=None): ''' Log a message with a timestamp ''' when = datetime.now() if when else when print('%s:%s' % (when,message))