Dies lässt sich am besten an einem Beispiel verdeutlichen (alle Beispiele gehen von ast
importiert wird; beachten Sie, dass ich Python 2.7.1 verwende):
# 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)
Wie wir also sehen können, l[1:10]
ergibt einen AST-Knoten, dessen Slice zwei Kinder hat - lower
y upper
beide auf numerische Literale gesetzt - und eine leere dritte step
Kind. Aber [1:10:]
die wir als identisch ansehen würden, setzt seine Slice's step
Kind zu sein None
wörtlicher Ausdruck ( Name(id='None', ctx=Load())
).
Okay, dachte ich. Vielleicht behandelt Python l[1:10:]
y l[1:10]
als völlig verschiedene Arten von Ausdrücken. Die Python-Ausdruck-Referenz ( enlace ) schien darauf hinzudeuten; l[1:10]
ist ein einfaches Slicing, aber l[1:10:]
ist ein erweitertes Slicing (mit nur einem Slice Item).
Aber auch im Zusammenhang mit dem erweiterten Slicing wird das Schrittargument besonders behandelt. Wenn wir versuchen, die obere oder untere Grenze in einem erweiterten Slicing mit einem Slice-Element zu ignorieren, erhalten wir nur leere Kinder:
# 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)
Bei näherer Betrachtung stellt sich außerdem heraus, dass die AST diese Schnitte nicht einmal als erweiterte Schnitte behandelt. Hier sehen Sie, wie erweiterte Slicings tatsächlich aussehen:
# 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)
Meine Schlussfolgerung lautet also: Die AST behandelt immer die step
Parameter aus irgendeinem Grund besonders und, unabhängig davon, die Slice
AST-Knoten stellt eine lange Scheibe dar (ich nehme an, damit es nicht zwei verschiedene Basis Slice
Klassen- ShortSlice
y LongSlice
-(obwohl ich denke, dass dies vorzuziehen wäre) und so kann eine erweiterte Scheibe mit einem einzigen Element als normale Scheibe dargestellt werden. Slice
Knoten und wird aus irgendeinem Grund so gemacht. Es scheint mir einfach falsch zu sein, zu erlauben None
Parameter als Standardwerte zu interpretieren, aber ich verstehe, dass dies eine bewusste Designentscheidung war; die None
wörtliche Einfügung und Behandlung langer Scheiben als Slice
Die Knotenpunkte wirken wie Unfälle (oder Artefakte alter Designs).
Hat sonst noch jemand eine fundiertere Erklärung?