Python 风格: 序列的泛型操作, 内置元组和映射类型, 用缩进来架构的源码, 无需变量声明的强类型等.
Python 从 ABC 语言继承了用统一风格处理序列数据. 数据结构都共用同一套操作: 迭代, 切片, 排序, 和拼接.
1. 内置序列的类型概览
容器序列: list, tuple, collections.deque 等能存放不同类型的数据的引用,
扁平序列: str, bytes, bytearray, memoryview和array.array 等只能容纳同一种类型的值.
序列类型还能按照能否被修改来分类
可变序列:(MutableSequence): list, bytearray, array.array等
不可变序列(Sequence): str, tuple 和 bytes
2. 列表推导和生成器表达式
列表推导, 通常只用于创建新的列表, 并且尽量简单. 避免其他操作, 例如用来重复获取一个函数的副作用
Python 会忽略代码里面[], {}, () 中的换行, 可以省略不好看的续行符
python3 中列表推导不会再有变量泄露问题, 即[]中变量, 影响到全局变量.
列表推导可以同 filter , map, zip等内置函数结合使用, 且速度不一定比lambda慢, eg: [ord(s) for s in symbols if ord(s) > 127]
生产器表达式, 主要用来节省内存. 当用作函数参数时, 只有它自己时, 可以省略一个括号, 即 tuple(ord(symbol) for symbobl in symbols)
3. 元组不仅仅是不可变的列表
元组即可用作不可变的列表, 还可以用于没有字段名的记录. eg: city, year, pop, chg, area = ('Tokyo', 2003, 32450, 0.66, 8014) # 元组拆包
*运算符, _占位符, 经常用在元组拆包中.
具名元组, collections.nametuple
工厂函数, 可以用来创建一个带字段名的元组和一个有名字的类
作为不可变的列表与list对比, 有一张方法和属性对比表2-1, 见P27
根据实用性, 列表常用来存放相同类型, 元组常用来存放不同类型, 也符合记录的本质
4. 切片
list, tuple, str等都支持切片操作
为什么切片和区间会忽略最后一个元素 - 当只有最后一个位置信息, 可以快速看出有几个元素. range(3), my_list[:3]
- 当起止位置都可见, 可以快速计算长度(stop-start) - 快速将序列拆成两个不重叠的部分, my_list[:x], my_list[x:]
- 符合其他同样以0开始的传统
切片背后, 其实是调用切片对象 slice(a, b, c), 在 10.4.1节有详细讲解
多维切片和省略一般用在numpy模块中
切片赋值, 值必须是iterable
5. 对序列使用运算符+, *, +=, *=
Python默认序列支持运算符+, *
, 注意前者需要两边由相同数据类型构成, 两个运算符返回值都是新建一个全新序列.
对于运算符*
需要特别注意, 存在嵌套的情况下, 复制的是索引即 [[1,2,3]]*2, --> [[1,2,3], [1,2,3]]
, 改变第一个列表, 第二个列表会跟随变化.
增量赋值的特殊方法__iadd__, __imul__ --> +=, *=, 找不到增量赋值的特殊方法就会调用+, *
, 注意对于可变序列会就地改变, 对于不可变序列会返回全新序列. 所以对不可变序列执行增量赋值会很慢.
另外, 有一些教训 - 不要将可变对象放在元组里面, eg: t=(1,2,[30,40]); t[2]+=[50,60], 会报错TypeError, 但t还是被改变了, 边界问题
- 增量赋值不是原子操作 - 查看 Python 的字节码并不难, dis.dis()函数, 对于理解代码背后运行机制很有帮助
6. list.sort方法和内置函数 sorted
list.sort 方法会就地排序, 内置函数 sorted 会返回全新列表.
两者有相同参数, reverse 和 key, key 接受仅一个参数的函数, 会将序列中每个元素先执行函数再比较. eg: key=str.lower 忽略大小写排序
两个排序算法都是稳定的, 采用自适应排序算法Timsort, 特点是交替使用插入排序和归并排序.
7. 其他
bisect模块包含两个函数, bisect和insort, 两者利用二分查找算法来在有序序列中查找或插入元素
检查一个元素是否出现在另一个集合中, 使用 set 更适合, set 专为检查元素是否存在做过优化
当列表不是首选, - 数组, 创建数组需要一个类型码, 即只能存放一种类型, 当处理千万浮点数的时候, 比列表明显更高效 - 内存视图, memoryview 是一个内置类, 能让用户不复制内容的情况下操作同一个数组的不通过切片, 来自NumPy的启发. - NumPy, SciPy, 提供高阶数组和矩阵操作, Pandas和Blaze提供数据分析的工具 - 双向队列和其他形式的队列, 一般都实现了线程安全. - collections.deque(双向队列), - queue的Queue, LifoQueue, PriorityQueue. - multiprocessing, asyncio, heapq 等