为什么Python在切片步骤中插入None?

时间:2011-12-09 02:15:03

标签: python abstract-syntax-tree

这可以通过示例进行说明(所有示例都假定ast已导入;请注意我使用的是Python 2.7.1):

# 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都设置为数字文字 - 而空的第三个{{1}孩子。但我们认为相同的step将其切片的[1:10:]子项设置为step文字表达式(None)。

好的,我想。也许Python将Name(id='None', ctx=Load())l[1:10:]视为完全不同的表达式。 Python表达式引用(link)当然似乎表明了这一点; l[1:10]是一个简单的切片,但l[1:10]是一个扩展切片(只有一个切片项)。

但是,即使在扩展切片的上下文中,也会特别处理step参数。如果我们尝试用一个切片项忽略扩展切片中的上限或下限,我们最终会得到空子:

l[1:10:]

此外,经过进一步检查,AST甚至不会将这些切片视为延长切片。这是扩展切片的实际情况:

# 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始终将# 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) 参数视为特殊的,并且无关地,step AST节点表示一个长切片(我想所以没有必要是两个不同的基类Slice类 - SliceShortSlice - 虽然我认为这是首选的)因此单项扩展切片可以表示为正常{{1}由于某种原因,节点已完成。允许LongSlice参数被解释为默认值似乎是错误的,但我理解这是一个有目的的设计决策;将Slice文字插入和处理长切片视为None节点似乎有点像事故(或旧设计的工件)。

其他人是否有更明智的解释?

1 个答案:

答案 0 :(得分: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