2011-12-09 33 views
5

这可以最好地举例(所有的例子假定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节点有两个孩子 - lowerupper都设置为数字文字 - 一个空的第三个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节点代表长片(我想是有别必须是两个不同的基地SliceShortSliceLongSlice - 虽然我认为这将是首选),所以单项扩展切片可以表示为正常的Slice节点,并且由于某种原因完成。对我来说,允许None参数被解释为默认值似乎是错误的,但我知道这是一个有意义的设计决定; None字面插入和处理长片段看起来有点像事故(或旧设计的文物)。

其他人有更明智的解释吗?

回答

3

没有在扩展切片符号这样的待遇,你将无法l[1:]l[1::]区分,你不能调用不同的特殊方法 - __getslice__可调用的垂直切片,但__getitem__必须调用一个扩展切片。

所以它主要是为Python 2.x中,已经在Python 3.x中消失了向后兼容性的事情:

Python 3.2 (r32:88445, Mar 25 2011, 19:28:28) 
[GCC 4.5.2] on linux2 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import ast 
>>> ast.dump(ast.parse("l[1:]").body[0].value.slice) 
'Slice(lower=Num(n=1), upper=None, step=None)' 
>>> ast.dump(ast.parse("l[1::]").body[0].value.slice) 
'Slice(lower=Num(n=1), upper=None, step=None)' 
>>> 

更多信息,请参见python2.7 source for ast.cdata model description