Python

丰富的序列

列表推导式、元组、拆包与内存视图:Python 序列的一组例子和小陷阱。

· 6 min read · Revised 23 Oct 2026

内置序列概览

  • 容器序列(container sequences): list, tuple, collections.deque

    • 存放对象的引用
  • 扁平序列(flat sequences):str, bytes, array.array

    • 在自己的内存空间存储内容值
  • CPython 对象头包含实现相关的元数据(其他 Python 实现不必使用相同布局)

    • float: ob_refcnt, ob_type, ob_fval
  • 可变序列(Mutable sequences): list, bytearray, array.array, collections.deque

  • 不可变序列(Immutable sequences): tuple, str, bytes

列表推导式/生成器表达式

  • List Comprehensions(listcomps) and Generator Expressions(genexps)

In Python code, line breaks are ignored inside pairs of [], {}, or (). So you can build multiline lists, listcomps, tuples, dictionaries, etc., without using the \ line continuation escape, which doesn’t work if you accidentally type a space after it.

  • “Walrus operator” :=:在推导式中,赋值表达式的目标绑定到外层作用域;循环变量仍属于推导式内部作用域。下面的 last 能在推导式外访问,c 则不能。
>>> x = 'ABC'
>>> codes = [ord(x) for x in x]
>>> x 
'ABC'
>>> codes
[65, 66, 67]
>>> codes = [last := ord(c) for c in x]
>>> last 
67
>>> c
	File "<stdin>", line 1, in <module> 
NameError: name 'c' is not defined
# INVALID
x := 0
# Valid alternative
(x := 0)
# INVALID
x = y := 0
# Valid alternative
x = (y := 0)
# Valid
len(lines := f.readlines())
# Valid
foo(x := 3, cat='vector')
# INVALID
foo(cat=category := 'vector')
# Valid alternative
foo(cat=(category := 'vector'))
  • Differences between assignment expressions and assignment statements
-   Multiple targets are not directly supported:
    x = y = z = 0  # Equivalent: (z := (y := (x := 0)))
    
-   Single assignment targets other than a single `NAME` are not supported:
    
    # No equivalent
    a[i] = x
    self.rest = []
    
-   Priority around commas is different:
    
    x = 1, 2  # Sets x to (1, 2)
    (x := 1, 2)  # Sets x to 1
    
-   Iterable packing and unpacking (both regular or extended forms) are not supported:
    
    # Equivalent needs extra parentheses
    loc = x, y  # Use (loc := (x, y))
    info = name, phone, *rest  # Use (info := (name, phone, *rest))
    
    # No equivalent
    px, py, pz = position
    name, phone, email, *other_info = contact
    
-   Inline type annotations are not supported:
    
    # Closest equivalent is "p: Optional[int]" as a separate declaration
    p: Optional[int] = None
    
-   Augmented assignment is not supported:
    total += tax  # Equivalent: (total := total + tax)
  • 列表推导式与map/filter比较,有时候可读性更强,性能方面相差不大
>>> symbols = '$¢£¥€¤'
>>> beyond_ascii = [ord(s) for s in symbols if ord(s) > 127]
>>> beyond_ascii
[162, 163, 165, 8364, 164]
>>> beyond_ascii = list(filter(lambda c: c > 127, map(ord, symbols)))
>>> beyond_ascii
[162, 163, 165, 8364, 164]
  • 生成器表达式通过迭代器逐个产生项,而不是构建一个列表提供给其他构造函数
line_list = ['  line 1\n', 'line 2  \n', ' \n', '']
# Generator expression -- returns iterator
stripped_iter = (line.strip() for line in line_list)
# List comprehension -- returns list
stripped_list = [line.strip() for line in line_list]
  • array
    • array.typecodes:可用类型码随 Python 版本变化,在当前解释器中查询
    • the type of objects stored in them is constrained

元组

  • Tuples hold records: each item in the tuple holds the data for one field, and the position of the item gives its meaning.
    • print with operator ’%’ can unpack tuple
  • Tuples as Immutable Lists:
    • When you see a tuple in code, you know its length will never change.
    • A tuple uses less memory than a list of the same length, and it allows Python to do some optimizations.
  • hash 能判断对象是否可哈希,但不能一般性地证明其内容不会变化。元组可哈希要求各元素可哈希;自定义可变对象也可能可哈希。下面这个函数实际检查的是可哈希性。
def is_hashable(o):
    try:
        hash(o)
    except TypeError:
        return False
    return True

tf = (10, 'alpha', (1, 2))  # Contains no mutable items
tm = (10, 'alpha', [1, 2])  # Contains a mutable item (list)
is_hashable(tf) # True
is_hashable(tm) # False

序列和可迭代对象拆包

  • parallel assignment
>>> lax_coordinates = (33.9425, -118.408056)
>>> latitude, longitude = lax_coordinates # unpacking
>>> latitude 
33.9425

>>> divmod(20, 8) 
(2, 4)
>>> t = (20, 8)
>>> divmod(*t)
(2, 4)
>>> quotient, remainder = divmod(*t)
>>> quotient, remainder 
(2, 4)

>>> import os
>>> _, filename = os.path.split('/home/luciano/.ssh/id_rsa.pub')
>>> filename
'id_rsa.pub'
  • 在序列拆包赋值中,一个目标列表可以有一个星号目标,位置不必在最后;它收集剩余项。
    • 函数定义中的 *args 与调用时的 *iterable 是相关但不同的语法,分别遵循函数参数和调用规则。
>>> a, b, *rest = range(5)
>>> a, b, rest 
(0, 1, [2, 3, 4])
>>> a, *b, rest = range(4)
>>> a, b, rest 
(0, [1, 2], 3)
>>> a, b, *rest = range(2)
>>> a, b, rest 
(0, 1, [])
>>> *a, = range(5)
>>> a
[0, 1, 2, 3, 4]

>>> *range(4), 4
(0, 1, 2, 3, 4)

A Small Puzzle

Example 2-16. A riddle

>>> t = (1, 2, [30, 40])
>>> t[2] += [50, 60]

What happens next? Choose the best answer:

  • A. t becomes (1, 2, [30, 40, 50, 60]).
  • B. TypeError is raised with the message ‘tuple’ object does not support item assignment.
  • C. Neither.
  • D. Both A and B.

答案是 D:列表先原地扩展,随后对元组元素赋值时报错。以下反汇编是旧版 CPython 输出;具体指令随版本变化。

>>> import dis
>>> dis.dis('s[a] += b')
  1           0 LOAD_NAME                0 (s)
              2 LOAD_NAME                1 (a)
              4 DUP_TOP_TWO
              6 BINARY_SUBSCR # Put the value of s[a] on TOS (Top Of Stack)
              8 LOAD_NAME                2 (b)
             10 INPLACE_ADD # Perform add
             12 ROT_THREE
             14 STORE_SUBSCR # Assign
             16 LOAD_CONST               0 (None)
             18 RETURN_VALUE

List.sort与内置函数sorted

  • List.sort method sorts a list in place without making a copy(use Timsort)
  • The built-in function sorted creates a new list and returns it
  • Accept both reverse and key(function)

When a List Is Not the Answer

  1. If a list only contains numbers, an array.array is a more efficient replacement. Arrays support all mutable sequence operations (including .pop, .insert, and .extend), as well as additional methods for fast loading and saving, such as .frombytes and .tofile.
  2. The built-in memoryview class is a shared-memory sequence type that lets you handle slices of arrays without copying bytes.
>>> from array import array
>>> octets = array('B', range(6))
>>> m1 = memoryview(octets)
>>> m1.tolist()
[0, 1, 2, 3, 4, 5]
>>> m2 = m1.cast('B', [2, 3])
>>> m2.tolist() 
[[0, 1, 2], [3, 4, 5]]
>>> m3 = m1.cast('B', [3, 2])
>>> m3.tolist() 
[[0, 1], [2, 3], [4, 5]]
>>> m2[1,1] = 22
>>> m3[1,1] = 33 
>>> octets 
array('B', [0, 1, 2, 33, 22, 5])
  1. NumPy implements multidimensional, homogeneous arrays and matrix types that hold not only numbers but also user-defined records, and provides efficient element-wise operations.
  2. Deques and Other Queues

校订依据

Find a note

Search titles and the full text of published notes.