Это лучше всего проиллюстрировать на примере (все примеры предполагают, что 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, у которого есть два дочерних элемента - lower
и upper
, оба из которых имеют числовые литералы, - и пустой третий дочерний элемент step
.Но [1:10:]
, который мы могли бы считать идентичным, устанавливает дочерний элемент step
его среза в буквальное выражение None
(Name(id='None', ctx=Load())
).
Хорошо, подумал я.Возможно, 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 даже не рассматривает эти срезы какрасширенные нарезки.Вот как на самом деле выглядят расширенные срезы:
# 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
специально по какой-то причине, и, независимо от этого, узел Slice
AST представляет длинный срез(Я полагаю, что не должно быть двух разных базовых Slice
классов - ShortSlice
и LongSlice
- хотя я думаю, что это будет предпочтительным), и поэтому расширенный срез из одного элемента может быть представлен как обычныйSlice
узел и делается по какой-то причине.Мне просто кажется неправильным интерпретировать параметры None
как значения по умолчанию, но я понимаю, что это было целенаправленное проектное решение;буквенная вставка None
и обработка длинных срезов как узлов Slice
просто кажутся случайностями (или артефактами старых конструкций).
У кого-нибудь есть более информированное объяснение?