• 切片要尽可能写得简单一些:如果从头开始选取,就省略起始下标 0 ;如果选到序列末尾,就省略终止下标。
  • 切片允许起始下标或终止下标越界,所以很容易就能表达“取开头多少个元素”(例如 a[:20])或“取末尾多少个元素”(例如 a[-20:0])等含义,而不用担心切片是否真有这么多元素。
  • 切片放在赋值符号的左侧可以将原列表中这段范围内的元素用赋值符号右侧的元素替换掉,但可能会改变原列表的长度

    凡是实现了 getitemsetitem 这两个特殊方法的类都可以切割(参见第 43 条)

开头与结尾

  • 如果是从头开始切割列表,那就应该省略冒号左侧的下标 0,这样看起来更清晰。

    1. assert a[:5] == a[0:5]
  • 如果一直取到列表末尾,那就应该省略冒号右侧的下标,因为用不着专门把它写出来。

    1. assert a[5:] == a[5:len(a)]

    允许起始或终止下标越界

  • 如果起点与终点所确定的范围超出了列表的边界,那么系统会自动忽略不存在的元素。

  • 但直接访问列表时候不能!
  • 利用这项特性,很容易就能构造出一个最多只有若干元素的输入序列,例如:

    1. first_twenty_items = a[:20]
    2. last_twenty_items = a[-20:]

    切割出来的列表是一份全新的列表

  • 切割出来的列表是一份全新的列表。

  • 即便把这个全新的列表中某个元素换掉,也不会影响原列表中的相应位置。
  • 原始列表那个位置上的元素还是旧值。

    1. a = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
    2. b = a[3:]
    3. print('Before: ', b)
    4. b[1] = 99
    5. print('After: ', b)
    6. print('No change:', a)

    image.png

    切片在左侧-换掉某些元素(长度可能变)

    1. a = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
    2. print('Before ', a)
    3. a[2:7] = [99, 22, 14]
    4. print('After ', a)

    image.png

    副本与引用

    副本

  • 起止位置都留空的切片,如果出现在赋值符号右侧,那么表示给这个列表做副本,

  • 这样制作出来的新列表内容和原列表相同,但身份不同。

    1. a = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
    2. b = a[:]
    3. assert b == a and b is not a
    4. # 无输出报错
    5. # 说明 a 和 b 的值相同,但是 a 和 b 是不同的引用

    引用

  • 把不带起止下标的切片放在赋值符号左边,表示是用右边那个列表的副本把左侧列表的全部内容替换掉

  • 同一引用,改变其中一个变量的值后,另外一个值也会变的
    1. a = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
    2. b = a
    3. print('Before a', a)
    4. print('Before b', b)
    5. a[:] = [101, 102, 103]
    6. assert a is b # Still the same list object
    7. print('After a ', a) # Now has different contents
    8. print('After b ', b) # Same list, so same contents as a
    image.png