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

时间:2016-09-20 18:01:14

标签: python python-3.x 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

4 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分:2)

slice_list应包含与要编入索引的对象一样多的“维度”。我所知道的任何Python库对象都没有使用多维功能,但您可以使用numpy轻松测试它:

import numpy as np
a = np.array([[1, 2], [3, 4]])
a[0:1, 0]

Python语言中有许多此类功能未直接在主库中使用。 __matmul__魔术方法(@运算符)是另一个例子。

答案 2 :(得分:2)

请注意,语法的结构方式允许两件事:

  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)
    9. 还有一些其他模式(x:y::y等),但每种模式都可以 是上述其中一种的变体。

    10. 切片文字只能 [...]中使用,而不能在任意表达式中使用。

    11. 否则,逗号分隔列表将被视为与任何其他元组一样。当您编写类似f[1, 2:3, 5::7]的表达式时,f.__getitem__会收到元组(1, slice(2, 3, None), slice(5, None, 7)作为其参数。使用该参数f.__getitem__ 所做的完全取决于type(f) __getitem__的实施。例如,列表和字符串仅接受intslice值作为参数,而dicts只接受可散列值。

答案 3 :(得分:1)

这不是语法问题,因此没有SyntaxError完全支持此语法list只是不知道如何处理你的切片。例如,一个虚拟类,它 nothing 但定义__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))

的Heck:

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中进一步阅读,您应该看到:

  

切片的语义如下。使用从切片列表构造的密钥对主数据库进行索引(使用与正常预订相同的__getitem__()方法),如下所示。 如果切片列表包含至少一个逗号,则该键是包含切片项转换的元组;否则,单个切片项的转换是关键。

(强调我的)