了解 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
。我们可以在语法允许的情况下提供切片,但是,由实现对象决定这些是否是支持的操作并对它们采取行动(如nparray
s做)或不做(并提出 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.
(强调我的)
请注意,以这种方式构造语法以允许两件事:
slice
字面值家族:
x:y:z == slice(x, y, z)
x:y == slice(x, y, None)
x: == slice(x, None, None)
x::z == slice(x, None, z)
::z == slice(None, None, z)
:y:z == slice(None, y, z)
:: == slice(None, None, None)
:y: == slice(None, y, None)
还有一些其他可能的模式(x:y:
、:y
等),但每个
是上述之一的变体。
切片字面量 只能 用于 [...]
,不能用于任意表达式。
否则,逗号分隔列表将被视为任何其他元组。当你写一个像 f[1, 2:3, 5::7]
这样的表达式时,f.__getitem__
会接收一个元组 (1, slice(2, 3, None), slice(5, None, 7)
作为它的参数。 f.__getitem__
对这个论点的作用完全取决于 type(f)
对 __getitem__
的实现。例如,列表和字符串只接受 int
和 slice
值作为参数,而字典只接受可哈希值。
以下是我从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
。我们可以在语法允许的情况下提供切片,但是,由实现对象决定这些是否是支持的操作并对它们采取行动(如nparray
s做)或不做(并提出 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.
(强调我的)
请注意,以这种方式构造语法以允许两件事:
slice
字面值家族:x:y:z == slice(x, y, z)
x:y == slice(x, y, None)
x: == slice(x, None, None)
x::z == slice(x, None, z)
::z == slice(None, None, z)
:y:z == slice(None, y, z)
:: == slice(None, None, None)
:y: == slice(None, y, None)
还有一些其他可能的模式(
x:y:
、:y
等),但每个 是上述之一的变体。切片字面量 只能 用于
[...]
,不能用于任意表达式。
否则,逗号分隔列表将被视为任何其他元组。当你写一个像 f[1, 2:3, 5::7]
这样的表达式时,f.__getitem__
会接收一个元组 (1, slice(2, 3, None), slice(5, None, 7)
作为它的参数。 f.__getitem__
对这个论点的作用完全取决于 type(f)
对 __getitem__
的实现。例如,列表和字符串只接受 int
和 slice
值作为参数,而字典只接受可哈希值。