了解 python 语言参考中描述的 python 切片语法

Understanding python slicings syntax as described in the python language reference

以下是我从The Python Language Reference复制的切片语法:

slicing      ::=  primary "[" slice_list "]"
slice_list   ::=  slice_item ("," slice_item)* [","]
slice_item   ::=  expression | proper_slice
proper_slice ::=  [lower_bound] ":" [upper_bound] [ ":" [stride] ]
lower_bound  ::=  expression
upper_bound  ::=  expression
stride       ::=  expression

根据我的理解,此语法等同于 SomeMappingObj[slice_item,slice_item etc...],后者又等同于 a[0:2:1,4:7:1]a =[i for i in range(20)]

但是,我无法在 IPython 中对此进行测试,而且我没有发现任何关于多重切片的问题。我对 python 中多重切片的解释是否正确?我做错了什么?

In [442]: a=[i for i in range(20)]

In [443]: a[0:12:2]
Out[443]: [0, 2, 4, 6, 8, 10]

In [444]: a[0:12:2,14:17:1]
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-444-117395d33bfd> in <module>()
----> 1 a[0:12:2,14:17:1]

TypeError: list indices must be integers or slices, not tuple

这是有效的语法,所以您没有得到 SyntaxError。它只是对 Python 列表没有意义或不受支持的操作。同样,"5" + fish 不是 SyntaxError,1/0 不是 SyntaxError,I.am.a.monkey 不是 SyntaxError。

您不能期望所有语法上有效的表达式都有意义。

一个 slice_list 应该包含与被索引的对象一样多的 "dimensions"。据我所知,任何 Python 库对象都没有使用多维功能,但您可以使用 numpy:

轻松测试它
import numpy as np
a = np.array([[1, 2], [3, 4]])
a[0:1, 0]

Python 语言中有许多这样的功能,它们不会在主库中直接使用。 __matmul__ 魔术方法(@ 运算符)是另一个例子。

这不是语法问题,因此没有 SyntaxError完全支持此语法list 只是不知道如何处理您的切片。以虚拟 class 为例,它 什么都不做 但定义 __getitem__ 接收订阅内容 []:

class DummySub:
    def __getitem__(self, arg):
        print(arg)

f = DummySub()

它只是打印它的 arg。我们可以在语法允许的情况下提供切片,但是,由实现对象决定这些是否是支持的操作并对它们采取行动(如nparrays做)或不做(并提出 TypeError):

f[1:2:3, 4:4:4]
(slice(1, 2, 3), slice(4, 4, 4))

见鬼:

f[1:2:3, 4:5:6, 7:8:9, ...]  # totally valid
(slice(1, 2, 3), slice(4, 5, 6), slice(7, 8, 9), Ellipsis)

通过在 reference for slicings 中进一步阅读,您应该看到:

The semantics for a slicing are as follows. The primary is indexed (using the same __getitem__() method as normal subscription) with a key that is constructed from the slice list, as follows. If the slice list contains at least one comma, the key is a tuple containing the conversion of the slice items; otherwise, the conversion of the lone slice item is the key.

(强调我的)

请注意,以这种方式构造语法以允许两件事:

  1. slice 字面值家族:

    1. x:y:z == slice(x, y, z)
    2. x:y == slice(x, y, None)
    3. x: == slice(x, None, None)
    4. x::z == slice(x, None, z)
    5. ::z == slice(None, None, z)
    6. :y:z == slice(None, y, z)
    7. :: == slice(None, None, None)
    8. :y: == slice(None, y, None)

    还有一些其他可能的模式(x:y::y 等),但每个 是上述之一的变体。

  2. 切片字面量 只能 用于 [...],不能用于任意表达式。

否则,逗号分隔列表将被视为任何其他元组。当你写一个像 f[1, 2:3, 5::7] 这样的表达式时,f.__getitem__ 会接收一个元组 (1, slice(2, 3, None), slice(5, None, 7) 作为它的参数。 f.__getitem__ 对这个论点的作用完全取决于 type(f)__getitem__ 的实现。例如,列表和字符串只接受 intslice 值作为参数,而字典只接受可哈希值。