awesome python 02 列表推导和生成器 元组 切片 排序 修改列表并保持有序

笔记:Fluent python 第二章 数组

  • 按存储类型分类

    • 容器序列 储存不同类型数据:listtuplecollections.deque
    • 扁平序列 储存相同类型数据:strbytesbytearraymemoryviewarray.array
  • 按可变与否分类

    • 可变 :listbytearrayarray.arraycollections.dequememoryview
    • 不可变:tuplestrbytes

列表推导和生成器

列表推导式

  • python3中不会出现2.x中出现的列表推导变量泄露
1
2
3
4
5
6
Python 2.7.12 (default, Nov 19 2016, 06:48:10)
x = 1
[x for x in range(10)]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
x
9
1
2
3
4
5
6
Python 3.5.2 (default, Nov 17 2016, 17:05:23)
x = 1
[x for x in range(10)]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> x
1
  • 列表推导能够达到filter、map组合起来的效果
1
2
beyond1 = [ord(s) for s in symbols if ord(s) > 127]
beyond2 = list(filter(lambda c: c > 127, map(ord, symbols)))
  • 生成笛卡尔积 外层的循环在列表推导式中靠前
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
>>> [(i, j) for i in range(2) for j in range(3)]
[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)]
```
* 使用生成器表达式 比 先使用列表推导生成全部元素再传入构造函数 要好的多
* 生成器表达式逐个产出元素,不会一次性产生所有元素然后遍历
```python
>>> for t in ((c, s) for c in range(2) for s in range(3)):
... print('%d %d' % t)
...
0 0
0 1
0 2
1 0
1 1
1 2

元组

元组特点

  1. 不可变
  2. 位置信息是对多个数据的记录

拆包

  1. 平行赋值

    1
    2
    a, b = (1, 2)
    a, b = b, a
  2. *号运算符

    • 把一个可迭代对象拆开作为函数的参数
      1
      2
      3
      4
      5
      6
      7
      8
      >>> divmod(20, 8)
      (2, 4)
      >>> divmod((20, 8))
      Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      TypeError: divmod expected 2 arguments, got 1
      >>> divmod(*(20, 8))
      (2, 4)
  3. _ * 占位符号

    • _ 可替代不关心的变量
    • * 可获取不确定数量的参数(only in python3)
1
2
3
>>> a, b, _, *rest, c = range(6)
>>> a, b, rest, c
(0, 1, [3, 4], 5)
  1. 嵌套拆包
    1
    2
    3
    >>> a, b, (c, d), e = (1, 2, (3, 4), (5, 6, 7))
    >>> a, b, c, d, e
    (1, 2, 3, 4, (5, 6, 7))

具名元组

  • 位于collections.nametuple
  • 类的实例和元组消耗内存相同,因为字段名在对应的类里
  • 初始化
    • City = nametuple('City', 'name country plpulation')
    • 第一个参数为类名
    • 第二个为包含数个字符串的可迭代对象 或 一个整个字符串以空格为分隔
  • 方法
    • _fields 返回所有字段名
    • _asdict 返回所有键值对

不可变性

  • 元组支持 s + s2拼接,不支持s += s2就地拼接
  • 只支持读操作类别的方法,比如包含、统计数量、取值、迭代、取长度

切片

  • 切片和区间会忽略最后一个元素
  • seq[start:end:step] 会调用 seq.__getitem__(slice(start, end, step))
  • 切片对象
    1. seq[slice(0, 6, 2)] = seq[0:6:2]
    2. name = slice(0, 6); print seq[name] 获得更好的可读性
  • 多维切片见numpy中矩阵的 a[m:n, i:j]
  • 给切片进行切除、修改
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    >>> l = list(range(20))
    >>> l
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
    # 删除切片
    >>> del(l[::2])
    >>> l
    [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
    # 修改切片
    # 前后数量不必一致
    >>> l[2:6] = [100]
    >>> l
    [1, 3, 100, 13, 15, 17, 19]
    # 前后数量需一致
    >>> l[1::2] = [1000, 2000, 3000]
    >>> l
    [1, 1000, 100, 2000, 15, 3000, 19]

序列的* 和 +

  • 两个操作都不会修改原有的操作对象,而是构建全新的序列
  • 如果序列内为某些变量的引用,*后可能只是得到几个相同变量的引用
    1
    2
    3
    4
    5
    6
    7
    >>> a = [ ['_']*3 ] * 3
    >>> a
    [['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']]
    >>> a[0][0] = 'o'
    >>> a
    [['o', '_', '_'], ['o', '_', '_'], ['o', '_', '_']]
    ]

序列的增量赋值

  • 如果序列存在__iadd__方法,会调用他进行就地加法
  • 如果不存在iadd,或序列不可变,会先调用__add__创建新的对象然后赋值给变量
  • 乘法对应的是__imul____mul__

+=的迷题

1
2
3
4
5
6
7
8
9
10
>>> t = (1, 2, [30, 40])
>>> t[2] += [50, 60]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> t
(1, 2, [30, 40, 50, 60])
>>> t[2].extend([70, 80])
>>> t
(1, 2, [30, 40, 50, 60, 70, 80])
  • 增值操作不是原子操作,尽管抛出异常仍完成了操作
  • 不要將可变对象放在元组里

排序

  • list.sort 就地排序,返回None
  • sorted 函数可传入可变不可变对象,新建一个列表作为返回值
  • sorted的key参数在max min itertools.groupby heapq.nlargest 也有体现#

修改列表并保持有序

  • biscet库可使用二分法查找某个元素应该插入有序列表的位置 biscet.biscet
  • 也可以直接查找位置并插入 biscet.insort
  • sortedcollection集成了biscet的功能,且更为强大