这可以最好地举例(所有的例子假定ast
是进口的,注意,我使用Python 2.7.1)所示:为什么Python将None插入切片步骤?
# Outputs: Slice(lower=Num(n=1), upper=Num(n=10), step=None)
ast.dump(ast.parse("l[1:10]").body[0].value.slice)
# Outputs: Slice(lower=Num(n=1), upper=Num(n=10), step=Name(id='None', ctx=Load()))
ast.dump(ast.parse("l[1:10:]").body[0].value.slice)
# Outputs: Slice(lower=Num(n=1), upper=None, step=None)
ast.dump(ast.parse("l[1:]").body[0].value.slice)
# Outputs: Slice(lower=None, upper=None, step=None)
ast.dump(ast.parse("l[:]").body[0].value.slice)
所以,我们可以看到,l[1:10]
导致其切片的AST节点有两个孩子 - lower
和upper
都设置为数字文字 - 一个空的第三个step
孩子。但是我们认为相同的[1:10:]
将其切片的step
子设置为文字表达式()。
好吧,我想。也许Python将l[1:10:]
和l[1:10]
视为完全不同的表达式。 Python表达式参考(link)当然似乎表示如此; l[1:10]
是一个简单的切片,但l[1:10:]
是一个扩展切片(只有一个切片项目)。
但是,即使在扩展切片的情况下,也会专门处理step参数。如果我们试图忽略上或者在一个片项目扩展切片下界,我们刚刚结束了空儿:
# Outputs: Slice(lower=Num(n=1), upper=None, step=Name(id='None', ctx=Load()))
ast.dump(ast.parse("l[1::]").body[0].value.slice)
# Outputs: Slice(lower=None, upper=Num(n=10), step=Name(id='None', ctx=Load()))
ast.dump(ast.parse("l[:10:]").body[0].value.slice)
而且,在进一步检查AST甚至不把这些slicings为扩展slicings 。下面是扩展slicings实际上是这样的:
# Outputs: ExtSlice(dims=[Slice(lower=None, upper=None, step=Name(id='None', ctx=Load())), Slice(lower=None, upper=None, step=Name(id='None', ctx=Load()))])
ast.dump(ast.parse("l[::, ::]").body[0].value.slice)
所以这是我的结论:AST始终把step
参数特殊出于某种原因,并unrelatedly的Slice
AST节点代表长片(我想是有别必须是两个不同的基地Slice
类ShortSlice
和LongSlice
- 虽然我认为这将是首选),所以单项扩展切片可以表示为正常的Slice
节点,并且由于某种原因完成。对我来说,允许None
参数被解释为默认值似乎是错误的,但我知道这是一个有意义的设计决定; None
字面插入和处理长片段看起来有点像事故(或旧设计的文物)。
其他人有更明智的解释吗?