知道怎么去分片


Python本身包含了如何将序列分片的语法。分片可以让你以最小的代价访问到子序列的某一项。最简单的使用方式是对Python内置的数据类型进行分片,如list(列表),str(字符串),bytes(字节数组)。最重要的是分片有很强的可实现性。对于实现了__getiten____setitem__这两个特殊方法的类都可以使用分片机制。(参考第28项:从集合,字符串继承来自定义容器)

简单分片

使用分片也很简单,基本形式是: somelist[start:end],当然,单独使用时startend必须在集合的下标范围内。

a = ['a','b','c','d','e','f'.'g','h']
print('First Four:',a[:4])
print('Last Four:',a[-4:])
print('Middle Two:',a[3:-3])
>>>
First Four: ['a','b','c','d']
Last Four: ['e','f','g','h']
Middle Two: ['d','e']

当分片是从头开始的话,下标0可以省略,来减少视觉干扰。 assert a[:5] == a[0:5]

同样的,当分片恰好到达尾部的时候,最后一个下标也是可以省略的。 assert a[5:] == a[5:len(a)]

分片中使用负数对于从后往前的操作很方便。负数的绝对值就是相对于末尾数据的偏移量。所有的形式对于新手而言也都是清晰的。作者也非常建议使用这些变量。

a[:]      # ['a','b','c','d','e','f','g','h']
a[:5]      # ['a','b','c','d','e']
a[:-1]     # ['a','b','c','d','e','f','g']
a[4:]      # ['e','f','g','h']
a[-3:]     # ['f'.'g','h']
a[2:5]     # ['c','d','e']
a[2:-1]     # ['c','d','e','f','g']
a[-3:-1]    # [ 'f','g']

分片机制将自动的处理超出集合边界的下标的取值。这也使得建立一个最大长度的输入序列更加的容易。

first_twenty_items = a[:20]
last_twenty_items = a[-20:0]

对比起来,直接索引到与上边相同的下标会引发一个异常


In [1]: a = ['a','b','c','d','e','f','g','h']

In [2]: a[8]
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-2-7749ee2033a3> in <module>()
----> 1 a[8]

IndexError: list index out of range

In [3]: a[:8]
Out[3]: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']

>>>
IndexError: list index out of range

发生这个异常的原因就在于分片机制下数字是指相对于开始位置的offset(偏移量),而单纯的使用下标的话还是需要遵守列表的访问规则的。

笔记: 使用负数作为分片变量来获取一个较好的数据集的情况还是很少发生的。例如,这样的一个表达式:somelist[-n:]也只是当n大于1的时候有效,当n0的时候,somelist[-0:]将返回当前列表的复制结果。

分片不改变原始数据

对一个列表进行分片,返回的仍然是一个列表。原来的列表仍然被维持不变,对返回的列表进行操作,不会影响原来的列表的值。

a = ['a','b','c','d','e','f','g','h']
b = a[4:]
print("Before:", b)
b[1] = 99
print("After:",b)
print("Original:",a)
>>>
Before: ['e','f','g','h']
After: ['e',99,'g','h']
Original: ['a','b','c','d','e','f','g','h']

赋值

当使用赋值语句的时候,分片将会替换原始列表中特定范围的值。而不像Tuple(元组)赋值那样(如 a, b = c[:2]),切片赋值的长度不必一定要与之相一致。分配片的赋值之前和之后的值将被保存。列表会相应的变大或者缩小来容纳新值。

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

如果省略开头索引和结尾索引,就会获得原始列表的拷贝版本。

b = a[:]
assert b ==a and b is not a

引用-变化-追随

当为列表赋值的时候省去开头和结尾下标的时候,将会用这个引用来替换整个列表的内容,而不是创建一个新的列表。同时,引用了这个列表的列表的相关内容,也会跟着发生变化。

b = a
print("Before:",a)
a[:] = [101,102,103]
assert a is b
print("After:",a)
>>>
Before: ['a','b','c','d','e','f','g','h']
After: [101,102,103]

备忘录:

  • 避免冗余:列表首尾的下标0,len(somelist)不必再列出。
  • 分片机制自动处理越界问题,但是最好在表达边界大小范围是更加的清晰。(如a[:20] 或者a[-20:]
  • 为一个列表赋值将会引起 应用该列表的其他列表相关的内容发生变化,即使他们的长度不相同。

results matching ""

    No results matching ""