Routineaufgaben mit Python automatisieren. Al Sweigart
Die Funktionen copy() und deepcopy() des Moduls copy
Verweise zu übergeben ist oft die sinnvollste Vorgehensweise, wenn eine Funktion tatsächlich die übergebene Liste oder das Dictionary bearbeiten soll. Es kann jedoch auch vorkommen, dass Sie die ursprüngliche Liste bzw. das Dictionary nicht ändern wollen. Für diesen Fall stellt Python das Modul copy bereit, das die Funktionen copy() und deepcopy() enthält. Mit copy.copy() können Sie eine echte Kopie eines veränderbaren Wertes wie einer Liste oder eines Dictionarys erstellen, also nicht einfach nur eine Kopie des Verweises darauf. Geben Sie folgenden Code in die interaktive Shell ein:
>>> import copy
>>> spam = ['A', 'B', 'C', 'D']
>>> id(spam)
57205555
>>> cheese = copy.copy(spam)
>>> id(cheese) # cheese ist eine andere Liste mit eigener Identität
57208888
>>> cheese[1] = 42
>>> spam
['A', 'B', 'C', 'D']
>>> cheese
['A', 42, 'C', 'D']
Hier verweisen die Variablen spam und cheese auf zwei unterschiedliche Listen, weshalb bei der Zuweisung von 42 zum Index 1 ausschließlich die Liste in cheese geändert wird. Wie Abb. 4–7 zeigt, verwenden die beiden Variablen nicht mehr dieselbe ID-Nummer, da sie nun auf verschiedene Listen verweisen.
Abb. 4–7cheese = copy.copy(spam) erstellt eine zweite Liste, die unabhängig von der ersten bearbeitet werden kann.
Wenn die Liste, die Sie kopieren wollen, selbst Listen enthält, verwenden Sie anstelle von copy.copy() die Funktion copy.deepcopy(). Damit werden auch die verschachtelten Listen kopiert.
Ein kurzes Programm: Conways Spiel des Lebens
Conways Spiel des Lebens ist ein zellulärer Automat, in dem das Verhalten eines aus diskreten Zellen bestehenden Spielfeldes durch einen Satz Regeln bestimmt wird. Außerdem erzeugt er eine recht hübsche Animation. Die einzelnen Schritte können Sie auch auf kariertes Papier zeichnen, wobei die Kästchen die Zellen darstellen. Ein ausgefülltes Kästchen »lebt«, ein leeres Kästchen ist »tot«. Eine lebende Zelle mit zwei oder drei lebenden Nachbarn lebt im nächsten Schritt weiter. Eine tote Zelle mit genau drei lebenden Nachbarn wird im nächsten Schritt lebendig. Alle anderen Zellen sterben im nächsten Schritt oder bleiben tot. Abb. 4–8 zeigt ein Beispiel für eine Folge von Schritten.
Abb. 4–8 Vier Schritte in Conways Spiel des Lebens
Trotz der einfachen Regeln treten viele überraschende Verhaltensweisen auf. In dem Spiel können sich Muster fortbewegen, selbst replizieren und sogar Computerprozessoren nachahmen. Die Grundlage für all diese komplexen Verhaltensweisen ist jedoch ein ziemlich einfaches Programm.
Das zweidimensionale Spielfeld können wir durch eine Liste aus Listen darstellen. Die inneren Listen sind dabei die einzelnen Spalten, wobei der String '#' für eine lebende Zelle steht und der String ' ' (also ein Leerzeichen) für eine tote. Geben Sie den folgenden Code in den Dateieditor ein und speichern Sie ihn als conway.py. Wenn Ihnen jetzt noch nicht alle Einzelheiten des Codes klar sein sollten, ist das kein Beinbruch. Geben Sie alles ein und versuchen Sie die Kommentare und Erklärungen so gut wie möglich nachzuvollziehen.
# Conways Spiel des Lebens
import random, time, copy
WIDTH = 60
HEIGHT = 20
# Erstellt eine Liste aus Listen für die Zellen
nextCells = []
for x in range(WIDTH):
column = [] # Erstellt eine neue Spalte
for y in range(HEIGHT):
if random.randint(0, 1) == 0:
column.append('#') # Fügt eine lebende Zelle hinzu
else:
column.append(' ') # Fügt eine tote Zelle hinzu
nextCells.append(column) # nextCells ist eine Liste aus Spaltenlisten
while True: # Hauptschleife des Programms
print('\n\n\n\n\n') # Trennt die einzelnen Schritte durch Zeilenumbrüche
currentCells = copy.deepcopy(nextCells)
# Gibt currentCells auf dem Bildschirm aus
for y in range(HEIGHT):
for x in range(WIDTH):
print(currentCells[x][y], end='') # Gibt # oder Leerzeichen aus
print() # Gibt am Zeilenende einen Zeilenumbruch aus
# Berechnet die Zellen des nächsten Schritts anhand der aktuellen Zellen
for x in range(WIDTH):
for y in range(HEIGHT):
# Ruft die Koordinaten der Nachbarn ab
# Durch % WIDTH liegt leftCoord immer zwischen 0 und WIDTH - 1
leftCoord = (x - 1) % WIDTH
rightCoord = (x + 1) % WIDTH
aboveCoord = (y - 1) % HEIGHT
belowCoord = (y + 1) % HEIGHT
# Zählt die lebenden Nachbarn
numNeighbors = 0
if currentCells[leftCoord][aboveCoord] == '#':
numNeighbors += 1 # Nachbarzelle oben links lebt
if currentCells[x][aboveCoord] == '#':
numNeighbors += 1 # Nachbarzelle oben lebt
if currentCells[rightCoord][aboveCoord] == '#':
numNeighbors += 1 # Nachbarzelle oben rechts lebt
if currentCells[leftCoord][y] == '#':
numNeighbors += 1 # Nachbarzelle links lebt
if currentCells[rightCoord][y] == '#':
numNeighbors += 1 # Nachbarzelle rechts lebt
if currentCells[leftCoord][belowCoord] == '#':
numNeighbors += 1 # Nachbarzelle unten links lebt
if currentCells[x][belowCoord] == '#':
numNeighbors += 1 # Nachbarzelle unten lebt
if currentCells[rightCoord][belowCoord] == '#':
numNeighbors += 1 # Nachbarzelle unten rechts lebt
# Bestimmt Zellenzustand nach den Regeln
if currentCells[x][y] == '#' and (numNeighbors == 2 or
numNeighbors == 3):