Python的切片表示法是如何工作的?也就是说:当我编写[x:y:z]、a[:]、a]::2]等代码时,我如何理解哪些元素最终会出现在切片中?请在适当的地方附上参考资料。


另请参见:为什么切片和范围上限是互斥的?


当前回答

Python切片表示法:

a[start:end:step]

对于开始和结束,负值被解释为相对于序列的结束。结束的正索引表示要包含的最后一个元素之后的位置。空白值默认如下:[+0:-0:1]。使用否定步骤会颠倒开始和结束的解释

该符号扩展到(numpy)矩阵和多维数组。例如,要分割整个列,可以使用:

m[::,0:2:] ## slice the first two columns

切片保存数组元素的引用,而不是副本。如果您想单独复制一个数组,可以使用deepcopy()。

其他回答

您可以使用切片语法返回字符序列。

指定用冒号分隔的开始和结束索引,以返回字符串的一部分。

例子:

获取从位置2到位置5的字符(不包括):

b = "Hello, World!"
print(b[2:5])

从开始切片

通过省略起始索引,范围将从第一个字符开始:

例子:

获取从开始到位置5的字符(不包括):

b = "Hello, World!"
print(b[:5])

切片到底

通过省略结束索引,范围将结束:

例子:

从位置2获取字符,一直到结尾:

b = "Hello, World!"
print(b[2:])

负索引

使用负索引从字符串末尾开始切片:实例

获取字符:

来自:“世界!”中的“o”(位置-5)

至,但不包括:“世界!”中的“d”(位置-2):

b = "Hello, World!"
print(b[-5:-2])

我有点沮丧,因为找不到一个准确描述切片功能的在线源代码或Python文档。

我接受了Aaron Hall的建议,阅读了CPython源代码的相关部分,并编写了一些Python代码,这些代码执行切片与CPython中的切片类似。我已经用Python 3对整数列表进行了数百万次随机测试。

您可能会发现我的代码中对CPython中相关函数的引用很有用。

def slicer(x, start=None, stop=None, step=None):
    """ Return the result of slicing list x.  

    See the part of list_subscript() in listobject.c that pertains 
    to when the indexing item is a PySliceObject.
    """

    # Handle slicing index values of None, and a step value of 0.
    # See PySlice_Unpack() in sliceobject.c, which
    # extracts start, stop, step from a PySliceObject.
    maxint = 10000000       # A hack to simulate PY_SSIZE_T_MAX
    if step is None:
        step = 1
    elif step == 0:
        raise ValueError('slice step cannot be zero')

    if start is None:
        start = maxint if step < 0 else 0
    if stop is None:
        stop = -maxint if step < 0 else maxint

    # Handle negative slice indexes and bad slice indexes.
    # Compute number of elements in the slice as slice_length.
    # See PySlice_AdjustIndices() in sliceobject.c
    length = len(x)
    slice_length = 0

    if start < 0:
        start += length
        if start < 0:
            start = -1 if step < 0 else 0
    elif start >= length:
        start = length - 1 if step < 0 else length

    if stop < 0:
        stop += length
        if stop < 0:
            stop = -1 if step < 0 else 0
    elif stop > length:
        stop = length - 1 if step < 0 else length

    if step < 0:
        if stop < start:
            slice_length = (start - stop - 1) // (-step) + 1
    else:
        if start < stop:
            slice_length = (stop - start - 1) // step + 1

    # Cases of step = 1 and step != 1 are treated separately
    if slice_length <= 0:
        return []
    elif step == 1:
        # See list_slice() in listobject.c
        result = []
        for i in range(stop - start):
            result.append(x[i+start])
        return result
    else:
        result = []
        cur = start
        for i in range(slice_length):
            result.append(x[cur])
            cur += step
        return result

通常,使用大量硬编码索引值编写代码会提高可读性以及维护混乱。例如,如果一年后你回到代码,你会看看它,想知道你写的时候在想什么只是一种更清楚地说明代码实际在做什么的方式。通常,内置slice()创建一个切片对象,可以在切片的任何位置使用允许。例如:

>>> items = [0, 1, 2, 3, 4, 5, 6]
>>> a = slice(2, 4)
>>> items[2:4]
[2, 3]
>>> items[a]
[2, 3]
>>> items[a] = [10,11]
>>> items
[0, 1, 10, 11, 4, 5, 6]
>>> del items[a]
>>> items
[0, 1, 4, 5, 6]

如果您有一个切片实例,您可以通过查看它的s.start、s.stop和s.step属性。例如:

>>>a=切片(10、50、2)>>>a.启动10>>>a.停止50>>>a.台阶2.>>>

枚举序列x语法允许的可能性:

>>> x[:]                # [x[0],   x[1],          ..., x[-1]    ]
>>> x[low:]             # [x[low], x[low+1],      ..., x[-1]    ]
>>> x[:high]            # [x[0],   x[1],          ..., x[high-1]]
>>> x[low:high]         # [x[low], x[low+1],      ..., x[high-1]]
>>> x[::stride]         # [x[0],   x[stride],     ..., x[-1]    ]
>>> x[low::stride]      # [x[low], x[low+stride], ..., x[-1]    ]
>>> x[:high:stride]     # [x[0],   x[stride],     ..., x[high-1]]
>>> x[low:high:stride]  # [x[low], x[low+stride], ..., x[high-1]]

当然,如果(高低)%步幅!=0,则终点将略低于高1。

如果步幅为负,则由于我们正在倒计时,顺序会有点改变:

>>> x[::-stride]        # [x[-1],   x[-1-stride],   ..., x[0]    ]
>>> x[high::-stride]    # [x[high], x[high-stride], ..., x[0]    ]
>>> x[:low:-stride]     # [x[-1],   x[-1-stride],   ..., x[low+1]]
>>> x[high:low:-stride] # [x[high], x[high-stride], ..., x[low+1]]

扩展切片(带逗号和省略号)通常仅用于特殊数据结构(如NumPy);基本序列不支持它们。

>>> class slicee:
...     def __getitem__(self, item):
...         return repr(item)
...
>>> slicee()[0, 1:2, ::5, ...]
'(0, slice(1, 2, None), slice(None, None, 5), Ellipsis)'

使用一点后,我意识到最简单的描述是它与for循环中的参数完全相同。。。

(from:to:step)

其中任何一项都是可选的:

(:to:step)
(from::step)
(from:to)

然后,负索引只需要将字符串的长度添加到负索引中即可理解它。

不管怎样,这对我来说都很有效。。。