a[:, 0, 7:9]
这就提出了一个问题:还有什么可能?(想象一下可能性!)
根据这个答案和一些实验(见下文),如果有逗号,Python会构建一个对象元组,其中一些可能是切片对象,并将其(作为key
)传递给a
的__getitem__(self, key)
。
__getitem__(..)
的文档没有指定这种行为。有没有我遗漏的官方文件?特别是,这种语法向后兼容的程度如何?(在网上搜索"python扩展切片表示法"会得到"python 2.3的新增功能",但没有提及。)
实验
>>> class Test(object):
... def __getitem__(self, x):
... print repr(x)
>>> t = Test()
首先,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
一些不允许的事情(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[ . . . . ]
任何都是可能的,只要它是有效的Python表达式。由[...]
之间的表达式生成的对象被传递给__getitem__
方法。就是这样。
逗号产生元组,表达式中的:
冒号产生slice()
对象。除此之外,你想用什么就用什么。
这是因为语法允许在符号中使用任何expression_list
。参见参考文件:
subscription ::= primary "[" expression_list "]"
切片在切片部分中进一步指定:
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
因此,再次允许任意expression
s,并且:
触发proper_slice
语法规则。
请注意,lower_bound
、upper_bound
和stride
表达式结果用于构造slice()
对象,该对象只能处理整数值。任何不能转换为整数的内容都将导致TypeError
被引发。这与语法错误不是一回事;t[1:...]
在语法上很好,但...
不可转换为整数,因此会出现运行时TypeError
异常。使用非整数切片值的两个示例在Python 2.4及更高版本上是不可能的。
实际的语法错误都源于无效的表达式。除了:
proper_slice
表示法之外,如果不能将[...]
之间的部分放在赋值的右侧,则也不能在切片中使用它。
例如,;
只能用于将多个简单语句放在一条逻辑线上。语句可以包含表达式,但表达式永远不能包含语句,从表达式中排除;
。(9:5),
不是一个有效的表达式(在Python中,您不能在括号中使用:
,parenth_form
规则不允许任何此类选项)。
用于切片的Python 2语法更为详细,因为...
是语法中的一个特定符号,并且您实际上不能在切片之外使用...
(在Python 3中,您可以在任何表达式有效的地方使用...
),这就是为什么t[(...)]
在Python 2中是一个语法错误,而在Python3中不是。
添加到前面的答案中。如果您定义
class Foo:
def __getitem__(self, key):
return key
做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))