简体   繁体   English

Python 的扩展切片符号的正式语法?

[英]Formal syntax of Python's extended slice notation?

Numpy, for example, allows multi-dimensional slices:例如 Numpy 允许多维切片:

a[:, 0, 7:9]

This raises the question: what else is possible?这就提出了一个问题:还有什么可能? (Imagine the possibilities!) (想象一下可能性!)

According to this answer and some experimentation (see below), if there is a comma, Python builds a tuple of objects, some of which may be slice objects, and passes it (as key ) to __getitem__(self, key) of a .根据这个答案和一些实验(见下文),如果有逗号, Python 构建一个对象元组,其中一些可能是切片对象,并将它(作为key )传递给__getitem__(self, key) of a

The documentation for __getitem__(..) doesn't specify this behaviour. __getitem__(..)的文档没有指定此行为。 Is there any official documentation that I missed?有没有我错过的官方文件? In particular, how backwards-compatible is this syntax?特别是,这种语法向后兼容的程度如何? (Searching the web for "python extended slice notation" gives "What's new in Python 2.3" , which doesn't mention it.) (在 web 中搜索“python extended slice notation”给出了“What's new in Python 2.3” ,但并未提及。)


Experimentation实验

>>> class Test(object):
...     def __getitem__(self, x):
...         print repr(x)


>>> t = Test()

First, things that Python finds recognisable for multi-slicing:首先,Python 发现可识别的多切片的东西:

>>> t[1]
1

>>> t['a':,]
(slice('a', None, None),)

>>> t['a':7:('b','c'),]
(slice('a', 7, ('b', 'c')),)

# Seems like it can be arbitrary objects?
>>> t[(t,t):[4,5]]
slice((<__main__.Test object at 0x07D04950>, <__main__.Test object at 0x07D04950>), [4, 5], None)

>>> t[::]
slice(None, None, None)

>>> t[:]
slice(None, None, None)

>>> t[::,1,::,::,:,:,:]
(slice(None, None, None), 1, slice(None, None, None), slice(None, None, None), slice(None, None, None),  slice(None, None, None), slice(None, None, None))

>>> t[...]
Ellipsis

>>> t[... , ...]
(Ellipsis, Ellipsis)

>>> t[  .   .      .    ]
Ellipsis

Some things that are NOT allowed (SyntaxError):一些不允许的事情(SyntaxError):

# Semicolon delimiter
t['a':5; 'b':7:-7]
# Slice within a slice
t['a':7:(9:5),]
# Two trailing commas
t[5,,]
# Isolated comma
t[,]
# Leading comma
t[,5]
# Empty string
t[]
# Triple colon
t[:::]
# Ellipses as part of a slice
t[1:...]
t[1:2:...]
# Ellipses inside no-op parens:
t[(...)]
# Any non-zero and non-three number of dots:
t[.]
t[..]
t[ .  .  .  . ]

Anything is possible, as long as it is a valid Python expression. 一切皆有可能,只要它是有效的Python表达式即可。 The object produced by the expression between [...] is passed to the __getitem__ method. [...]之间的表达式产生的对象将传递给__getitem__方法。 That's it. 而已。

Commas produce a tuple, : colons in an expression produce a slice() object. 逗号产生一个元组, :表达式中的冒号产生一个slice()对象。 Beyond that, use whatever you want. 除此之外,使用任何您想要的。

That's because the grammar allows for any expression_list in the notation. 这是因为语法允许在符号中包含任何expression_list See the reference documentation : 请参阅参考文档

 subscription ::= primary "[" expression_list "]" 

Slicing is further specified in the Slicings section : 切片在进一步指定Slicings部分

 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 

So again arbitrary expression s are allowed, and : triggers the proper_slice grammar rule. 因此,再次允许使用任意expression ,并且:触发proper_slice语法规则。

Note that the lower_bound , upper_bound and stride expression results are used to construct a slice() object, which can only handle integer values . 请注意, lower_boundupper_boundstride表达式结果用于构造slice()对象,该对象只能处理整数值 Anything that can't be converted to an integer will result in a TypeError being raised. 任何不能转换为整数的东西都将TypeError That's not the same thing as a syntax error; 这和语法错误是不一样的。 t[1:...] is syntactically just fine, but ... is not convertable to an integer so you get a runtime TypeError exception. t[1:...]从语法上讲还不错,但是...不可转换为整数,因此会出现运行时TypeError异常。 Your two examples using non-integer slice values are not possible on Python versions 2.4 and up at the very least. 您的两个使用非整数切片值的示例至少在Python 2.4及更高版本上是不可能的。

Your actual syntax errors all stem from invalid expressions. 您的实际语法错误均源自无效表达式。 Apart from the : proper_slice notation, if you can't put the part between [...] on the right-hand side of an assignment, you can't use it in a slice either. 除了: proper_slice表示法以外,如果您无法将部分放在[...]赋值的右侧,则也不能在切片中使用它。

For example, ; 例如, ; can only be used to put multiple simple statements on a single logical line. 只能用于将多个简单语句放在单个逻辑行上。 Statements can contain expressions, but expressions can never contain statements, excluding ; 语句可以包含表达式,但是表达式绝不能包含语句; from expressions. 从表达。 (9:5), is not a valid expression (nowhere else in Python could you use a : in parentheses, the parenth_form rule doesn't allow for any such options). (9:5),不是有效的表达式(在Python的其他任何地方,您都不能在括号中使用:parenth_form规则不允许任何此类选项)。

The Python 2 grammar for slicings is a little more elaborate in that ... is a specific notation in the grammar there, and you can't actually use the ... outside of slicings (in Python 3 you can use ... anywhere an expression is valid), which is why t[(...)] is a syntax error in Python 2 but not in Python 3. 用于切片Python 2语法更加精细,因为...是语法中的一种特定符号,您实际上不能在切片之外使用... (在Python 3中,您可以在任何地方使用...表达式有效),这就是为什么t[(...)]在Python 2中是语法错误,但在Python 3中不是语法错误的原因。

To add to the earlier answer.添加到较早的答案。 If you define如果你定义

class Foo:
    def __getitem__(self, key):
        return key

and do Foo()[0, :, 1:2, 1:2:3] it will give you the internal representation which is:并执行Foo()[0, :, 1:2, 1:2:3]它将为您提供内部表示:

>>> Foo()[0, :, 1:2, 1:2:3]
(0, slice(None, None, None), slice(1, 2, None), slice(1, 2, 3))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM