得之我幸 失之我命

when someone abandons you,it is him that gets loss because he lost someone who truly loves him but you just lost one who doesn’t love you.

向 Python 切片再进一步

切片是什么?

切片操作基本表达式:object[start_index:end_index:step]

一个完整的切片表达式包含两个 :,用于分隔三个参数 (start_index、end_index、step);当只有一个 : 时,默认第三个参数 step=1;当一个 : 也没有时,表示切取 start_index 指定的那个元素

step:正负数均可,其绝对值大小决定了切取数据时的步长,而正负号决定了切取方向,正表示从左往右取值,负表示从右往左取值;当 step 省略时,默认为 1,即从左往右以步长 1 取值

start_index:表示起始索引(包含该索引对应值);该参数省略时,表示从对象端点开始取值,至于是从起点还是从终点开始,由 step 的正负决定,step 为正从起点开始,为负从终点开始

end_index:表示终止索引(不包含该索引对应值);该参数省略时,表示一直取到数据端点,至于是到起点还是到终点,同样由 step 的正负决定,step 为正时直到终点,为负时直到起点

切片常规操作详解

1
2
3
4
>>> a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# +index 0 1 2 3 4 5 6 7 8 9
# -index -10 -9 -8 -7 -6 -5 -4 -3 -2 -1
  1. 获取某个元素

    1
    2
    3
    4
    5
    >>> a[1]
    1

    >>> a[-2]
    8
  2. 获取完整对象

    1
    2
    3
    4
    5
    6
    7
    8
    >>> a[:]
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

    >>> a[::]
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

    >>> a[::-1] # 逆序输出
    [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
  3. 切片获取部分元素

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    # step=1,从左往右取值
    >>> a[1:6] # start_index=1 到 end_index=6 同样表示从左往右取值
    [1, 2, 3, 4, 5]

    >>> a[6:2] # start_index=6 到 end_index=2 决定了从右往左取值,和 step 方向矛盾,所以为空
    []

    >>> a[:6] # start_index 省略,从 0 开始一直取到 end_index=6(该点不包括)
    [0, 1, 2, 3, 4, 5]

    >>> a[6:] # 从 start_index=6 开始,一直取到终点值 9
    [6, 7, 8, 9]

    >>> a[-1:-6] # start_index=-1 到 end_index=-6 决定了从右往左取值,和 step 方向矛盾,所以为空;索引 -1 在 -6 的右边
    []

    >>> a[-6:-1] # start_index=-6 到 end_index=-1 同样是从左往右取值;索引 -6 在 -1 的左边
    [4, 5, 6, 7, 8]

    >>> a[:-6] # 从 0 开始一直取到 end_index=-6(该点不包括)
    [0, 1, 2, 3]

    >>> a[-6:] # 从 start_index=-6 开始,一直取到终点值 9
    [4, 5, 6, 7, 8, 9]

    >>> a[1:-6] # start_index=1 在 end_index=-6 的左边,因此从左往右取值
    [1, 2, 3]

    >>> a[-1:6] # start_index=-1 在 end_index=6 的右边,因此从右往左取值,和 step 方向矛盾,因此为空
    []


    # setp=-1,从右往左取值
    >>> a[1:6:-1] # start_index=1 到 end_index=6 决定了从左往右取值,和 step 方向矛盾,所以为空
    []

    >>> a[:6:-1] # 从终点值 9 开始一直取到 end_index=6(该点不包括)
    [9, 8, 7]

    >>> a[6::-1] # 从 start_index=6 开始,一直取到起点 0
    [6, 5, 4, 3, 2, 1, 0]

    >>> a[-1:-6:-1] # start_index=-1 到 end_index=-6 同样是从右往左取值,索引 -1 在 -6 的右边
    [9, 8, 7, 6, 5]

    >>> a[:-6:-1] # 从终点开始一直取到 end_index=-6(该点不包括)
    [9, 8, 7, 6, 5]

    >>> a[-6::-1] # 从 start_index=-6 开始,一直取到起点
    [4, 3, 2, 1, 0]

    >>> a[1:-6:-1] # start_index=1 在 end_index=-6 的左边,因此从左往右取值,和 step 方向矛盾,因此为空
    []

    >>> a[-1:6:-1] # start_index=-1 在 end_index=6 的右边,从右往左取值
    [9, 8, 7]

一些少见的切片

  1. 多层切片

    1
    2
    >>> a[:8][2:5][-1:]
    [4]
  2. 切片操作的三个参数可以用表达式

    1
    2
    >>> a[2+1:3*2:7%3]  # a[2+1:3*2:7%3] = a[3:6:1]
    >>> [3, 4, 5]

一些骚气的切片

  1. 给切片赋值,等号后面必须是可迭代对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    >>> a[3:3] = ['1', '2']  # start_index >= end_index, step = 1,退化成插入元素,插入字符
    [0, 1, 2, '1', '2', 3, 4, 5, 6, 7, 8, 9]

    >>> a[3:3] = '12' # start_index >= end_index, step = 1,退化成插入元素,插入字符
    [0, 1, 2, '1', '2', 3, 4, 5, 6, 7, 8, 9]

    >>> a[3:3] = [12] # start_index >= end_index, step = 1,退化成插入元素,插入数字
    [0, 1, 2, 12, 3, 4, 5, 6, 7, 8, 9]

    >>> a[3:3] = 12 # 等号后面不是可迭代对象,报错
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    TypeError: can only assign an iterable

    >>> a[3:5] = ['1', '2'] # start_index < end_index, step = 1,等号后面的对象长度 = end_index - start_index,用字符替换元素
    [0, 1, 2, '1', '2', 5, 6, 7, 8, 9]

    >>> a[3:7] = [11, 12] # start_index < end_index, step = 1,等号后面的对象长度 < end_index - start_index,用字符替换切片元素,并删除 a 切片范围内中多出来的元素
    [0, 1, 2, 11, 12, 7, 8, 9]

    >>> a[3:4] = 'ab' # start_index < end_index, step = 1,等号后面的对象长度 > end_index - start_index,用字符替换切片元素,并插入可迭代对象中多出来的元素到 a 中
    [0, 1, 2, 'a', 'b', 4, 5, 6, 7, 8, 9]

    >>> a[0:4:2] = 'ab' # step != 1,等号后面的对象长度必须等于切片长度,否则报错,用字符替换切片元素
    ['a', 1, 'b', 3, 4, 5, 6, 7, 8, 9]

    >>> a[6:4:-1] = 'ab' # step != 1,等号后面的对象长度必须等于切片长度,否则报错,用字符替换切片元素
    [0, 1, 2, 3, 4, 'b', 'a', 7, 8, 9]

    >>> a[6:4:-2] = 'abcd' # step != 1,等号后面的对象长度不等于切片长度,报错
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    ValueError: attempt to assign sequence of size 4 to extended slice of size 1
  2. 切片拷贝

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    # 单层元素拷贝
    >>> b = a[:]
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

    # 多层元素的拷贝
    >>> b = [1, 2, ['A', 'B']]
    >>> c = b[:]
    >>> c[0] = 9 # 修改 b 的最外层元素,将 1 变成 9
    >>> c[2][0] = 'D' # 修改 b 的内嵌层元素
    >>> b
    [1, 2, ['D', 'B']] # c 修改内嵌层元素 A 为 D 后,b 中的 A 也变成了 D,说明共享内部嵌套元素,但外层元素 1 没变
    >>> c
    [9, 2, ['D', 'B']] # 修改后的 c
    >>> id(b)
    15831560
    >>> id(c)
    15833576 # b,c 的内存地址是不同的

    [:] 和 .copy() 都属于浅拷贝,只拷贝最外层元素,内层嵌套元素通过引用方式共享,非独立分配内存,如果需要彻底拷贝则需采用深拷贝

    关于拷贝的问题,后面再展开

be yourself, everyone else is already taken.