Wie zerlegt man eine Liste, einen String oder ein Tupel – Teil 2

Slice-Objekte mit slice() erstellen

Man kann ein Slice-Objekt mit der built-in Funktion slice() erstellen. Um die Elemente wiederholt an der gleichen Position auszuwählen, kann man das Slice-Objekt einmal erstellen und danach wiederverwenden.

slice(start, stop, step) ist gleichbedeutend mit start:stop:step.

l = [0, 10, 20, 30, 40, 50, 60]

sl = slice(2, 5, 2)
print(sl)
# slice(2, 5, 2)

print(type(sl))
# <class 'slice'>

print(l[sl])
# [20, 40]

Wenn zwei Argumente angegeben werden, wird step auf None gesetzt. Dies ist gleichbedeutend mit [start:stop].

sl = slice(2, 5)
print(sl)
# slice(2, 5, None)

print(l[sl])
# [20, 30, 40]

Wenn nur ein Argument angegeben wird, werden start und step auf None gesetzt. Dies ist gleichbedeutend mit [:stop].

sl = slice(2)
print(sl)
# slice(None, 2, None)

print(l[sl])
# [0, 10]

Wenn alle Argumente weggelassen werden, wird ein TypeError ausgelöst. Wenn man ein Slice-Objekt erstellen möchten, das [:] entspricht, gibt man explizit None an.

# sl = slice()
# TypeError: slice expected at least 1 arguments, got 0

sl = slice(None)
print(sl)
# slice(None, None, None)

print(l[sl])
# [0, 10, 20, 30, 40, 50, 60]

Werte mit Hilfe von Slices zuweisen

Man kann dem durch Slices ausgewählten Bereich neue Werte zuweisen.
Dabei spielt es keine Rolle, ob die Anzahl der Positionen in dem durch Slicing ausgewählten Bereich mit der Anzahl der zuzuordnenden Positionen (= die Länge des Objekts) übereinstimmt.

Beispiele

l = [0, 10, 20, 30, 40, 50, 60]

l[2:5] = [200, 300, 400]
print(l)
# [0, 10, 200, 300, 400, 50, 60]

l[2:5] = [-2, -3]
print(l)
# [0, 10, -2, -3, 50, 60]

l[2:4] = [2000, 3000, 4000, 5000]
print(l)
# [0, 10, 2000, 3000, 4000, 5000, 50, 60]

l[2:6] = [20000]
print(l)
# [0, 10, 20000, 50, 60]

Es ist zu beachten, dass die Zuweisung eines Einzelwerts zu einem TypeError führt.

# l[2:3] = 200
# TypeError: can only assign an iterable

l[2:3] = [200]
print(l)
# [0, 10, 200, 50, 60]

Wenn die rechte Seite leer ist, werden die Elemente in dem vom Slice ausgewählten Bereich gelöscht.

l[1:4] = []
print(l)
# [0, 60]

Man kann auch einen Bereich außerhalb des Bereichs oder einen leeren Bereich angeben. Der Wert auf der rechten Seite wird an der angegebenen Position eingefügt.

l = [0, 10, 20, 30, 40, 50, 60]

l[100:200] = [-1, -2, -3]
print(l)
# [0, 10, 20, 30, 40, 50, 60, -1, -2, -3]

l[2:2] = [-100]
print(l)
# [0, 10, -100, 20, 30, 40, 50, 60, -1, -2, -3]

Wenn die Anzahl der Elemente für den Bereich, in dem step angegeben ist, nicht gleich ist, wird ein ValueError ausgelöst.

l = [0, 10, 20, 30, 40, 50, 60]

l[1::2] = [100, 200, 300]
print(l)
# [0, 100, 20, 200, 40, 300, 60]

l[1::2] = [100, 200]
# ValueError: attempt to assign sequence of size 2 to extended slice of size 3

Um ein Element in der Mitte oder am Ende der Liste hinzuzufügen, kann man auch die Methoden insert() und append() verwenden.

Slices auf eine Liste von Listen anwenden

Wenn ein Slice auf eine Liste von Listen (= 2D-Liste) angewendet wird, werden die inneren Listen ausgewählt.

l_2d = [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]]

print(l_2d[1:3])
# [[3, 4, 5], [6, 7, 8]]

Um ein Slice auf die inneren Listen anzuwenden, verwendet man List Comprehensions.

print([l[:2] for l in l_2d[1:3]])
# [[3, 4], [6, 7]]

Wenn man eine Spalte erhalten möchten, kann man sie transponieren.

l_2d_t = [list(x) for x in zip(*l_2d)]
print(l_2d_t)
# [[0, 3, 6, 9], [1, 4, 7, 10], [2, 5, 8, 11]]

print(l_2d_t[1])
# [1, 4, 7, 10]

Hier ist zu beachten, dass es einfacher ist, mit NumPy mehrdimensionale Arrays zu manipulieren. In NumPy kann man für jede Dimension ein Slice wie z.B. [1:4, 2:5] angeben.

Slices erzeugen eine flache Kopie

Wenn eine Liste beispielsweise aus unveränderlichen Objekten wie Zahlen besteht, hat die Zuweisung des Slicing-Ergebnisses an eine Variable und die Aktualisierung ihrer Elemente keine Auswirkungen auf das ursprüngliche Objekt.

l = [0, 10, 20, 30, 40, 50, 60]

l_slice = l[2:5]
print(l_slice)
# [20, 30, 40]

l_slice[1] = 300
print(l_slice)
# [20, 300, 40]

print(l)
# [0, 10, 20, 30, 40, 50, 60]

Wenn eine Liste veränderbare Objekte wie andere Listen oder Dictionaries enthält, wirkt sich eine Aktualisierung von Elementen in der kopierten Liste auch auf die ursprüngliche Liste aus.

l_2d = [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]]

l_2d_slice = l_2d[1:3]
print(l_2d_slice)
# [[3, 4, 5], [6, 7, 8]]

l_2d_slice[0][1] = 400
print(l_2d_slice)
# [[3, 400, 5], [6, 7, 8]]

print(l_2d)
# [[0, 1, 2], [3, 400, 5], [6, 7, 8], [9, 10, 11]]

Im obigen Beispiel wird durch die Aktualisierung der Liste im Slice auch die Liste im Originalobjekt aktualisiert. Ebenso wirkt sich eine Aktualisierung der Liste im Originalobjekt auch auf die Liste im Slice aus.

Um dies zu vermeiden, importiert man das Kopiermodul der Standardbibliothek und verwendet deepcopy().

import copy

l_2d = [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]]

l_2d_slice_deepcopy = copy.deepcopy(l_2d[1:3])
print(l_2d_slice_deepcopy)
# [[3, 4, 5], [6, 7, 8]]

l_2d_slice_deepcopy[0][1] = 400
print(l_2d_slice_deepcopy)
# [[3, 400, 5], [6, 7, 8]]

print(l_2d)
# [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]]

Slices für Strings und Tuple

Obwohl wir uns bisher auf Beispiele mit Listen konzentriert haben, können Slices auch auf andere Sequenzobjekte, wie Strings (str) und Tuples, angewendet werden.

Da str und tuple jedoch unveränderlich sind, kann man ihnen keine neuen Werte zuweisen!

s = 'abcdefg'

print(s[2:5])
# cde

print(s[::-1])
# gfedcba

# s[2:5] = 'CDE'
# TypeError: 'str' object does not support item assignment

t = (0, 10, 20, 30, 40, 50, 60)

print(t[2:5])
# (20, 30, 40)

# t[2:5] = (200, 300, 400)
# TypeError: 'tuple' object does not support item assignment