《Fluent Python》笔记 序列类型

内置序列类型

按照序列存放元素方式的不同,可以分为:

  • 容器序列:list、 tuple 和 collections.deque

  • 扁平序列:str、 bytes、 bytearray、 memoryview 和 array.array

    容器序列中存放的是元素对象的引用,扁平序列存放的是值。所以前者能够存放不同类型的数据,而后者只能存放单一类型数据。

按照序列类型能否被修改,可以分为:

  • 可变序列:list、 bytearray、 array.array、 collections.deque 和 memoryview
  • 不可变序列:tuple、 str 和 bytes

列表推导和生成器表达式

列表推导仅限于list对象的快捷构建生成器表达式可以用于创建任何类型的序列。

列表推导

示例:

1
2
a = [i for i in 'ABC']
a = [i * j for i in range(10) for j in range(10)] # 计算笛卡尔积

生成器表达式

生成器表达式和列表推导语法相似,不同之处在于前者为圆括号,后者为方括号。

1
2
symbols = '$¢£¥€¤'
tuple(ord(symbol) for symbol in symbols)

元组

元组除了为不可变列表外,还具有如下理解。

  • 元组的记录功能

    1
    2
    3
    lax_coordinates = (33.9425, -118.408056)
    city, year, pop, chg, area = ('Tokyo', 2003, 32450, 0.66, 8014)
    traveler_ids = [('USA', '31195855'), ('BRA', 'CE342567'), ('ESP', 'XDA205856')]

    元组的记录功能体现在,元组可以将一个对象的所有信息打包起来,这样这些信息就和对象个体实现了绑定的操作,在多个对象间进行操作时,不会将个体所携带的信息丢失。

  • 元组拆包

    普通拆包操作如下:

    1
    2
    lax_coordinates = (33.9425, -118.408056)
    latitude, longitude = lax_coordinates # 元组拆包

    * 运算符,将可迭代对象拆开作为函数参数。

    1
    2
    t = (1, 2)
    func(*t) // 等同func(1, 2)

    *args 获取不确定数量参数。

    1
    2
    3
    4
    5
    6
    >>> a, b, *rest = range(5)
    >>> a, b, rest
    (0, 1, [2, 3, 4])
    >>> a, *body, c, d = range(5)
    >>> a, body, c, d
    (0, [1, 2], 3, 4)
  • 嵌套元组拆包

    1
    i, j, (k, l) = (1, 2, (3, 4))
  • 具名元组

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    >>> from collections import namedtuple
    >>> City = namedtuple('City', 'name country population coordinates')
    >>> tokyo = City('Tokyo', 'JP', 36.933, (35.689722, 139.691667))
    >>> tokyo
    City(name='Tokyo', country='JP', population=36.933, coordinates=(35.689722,
    139.691667))
    >>> tokyo.population
    36.933
    >>> tokyo.coordinates
    (35.689722, 139.691667)
    >>> tokyo[1]
    'JP

    具名元组可以理解为一个只有属性没有方法的类对象,创建时接收两个参数:一个是类名,一个是类的各个属性的名字。

高级切片

  • 间隔取值

    1
    2
    3
    4
    5
    6
    7
    >>> s = 'bicycle'
    >>> s[::3]
    'bye'
    >>> s[::-1]
    'elcycib'
    >>> s[::-2]
    'eccb'

    s[a:b:c] 的形式对 sab之间以 c 为间隔取值。 c 的值为负表示反向取值。

  • 多维切片和省略符

    [a:b, c:d, e:f]三维切片。

    x[i, ...]x[i, :, :, :]的缩写。

  • 切片赋值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    >>> l = list(range(10))
    >>> l
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    >>> l[2:5] = [20, 30]
    >>> l
    [0, 1, 20, 30, 5, 6, 7, 8, 9]
    >>> del l[5:7]
    >>> l
    [0, 1, 20, 30, 5, 8, 9]
    >>> l[3::2] = [11, 22]
    >>> l
    [0, 1, 20, 11, 5, 22, 9]
    >>> l[2:5] = [100]
    >>> l
    [0, 1, 100, 22, 9]

    如果赋值对象是一个切片,=右边也必须是个可迭代对象。

list.sort方法和内置函数sorted

list.sort方法是对列表对象就地改动,即不会返回新列表,而是直接对原列表改变。内置函数sorted会新建一个列表返回。

用bisect来管理已排序的序列

bisect.bisect(seq, item)返回元素item插入到已排序序列seq中的位置索引。如果itemseq中已出现,那么插入到那个出现的值的右侧,bisect_left插入在左侧。

bisect.insort(seq, item)返回item插入序列seq中,并保持整个序列升序。

其他序列类型

  • 数组(array)

    对于只存放数字的序列,array比list更高效。

  • 内存视图(memoryview)

    用户可以在不复制内容的情况下操作同一个数组的不同切片。

  • 双向队列(collections.deque)

    双向队列,一个能够从两端添加或者删除元素的序列类型。对于大小固定的队列,满员后添加一个元素会在反向端删除一个元素。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    >>> from collections import deque
    >>> dq = deque(range(10), maxlen=10)
    >>> dq
    deque([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxlen=10)
    >>> dq.rotate(3)
    >>> dq
    deque([7, 8, 9, 0, 1, 2, 3, 4, 5, 6], maxlen=10)
    >>> dq.rotate(-4)
    >>> dq
    deque([1, 2, 3, 4, 5, 6, 7, 8, 9, 0], maxlen=10)
    >>> dq.appendleft(-1)
    >>> dq
    deque([-1, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxlen=10)
    >>> dq.extend([11, 22, 33])
    >>> dq
    deque([3, 4, 5, 6, 7, 8, 9, 11, 22, 33], maxlen=10)
    >>> dq.extendleft([10, 20, 30, 40])
    >>> dq
    deque([40, 30, 20, 10, 3, 4, 5, 6, 7, 8], maxlen=10)
  • 队列(queue)

    与双向列表不同,固定大小的队列满员后,其中元素将被锁住无法进行添加,知道某个线程移除某个元素腾出位置。