de
Python lernen
für Einsteiger & Fortgeschrittene
Autor: Axel Pratzner
Stand: Februar 2021
Über den Autor:
Axel Pratzner studierte an der
Universität Tübingen
Erwachsenenbildung/Weiterbildung.
Ich denke, dass die sprechende URLs aussagekräftig genug sind, um zu sehen, was
ich so mache :).
Bei längerem Programmiercode ist Copy & Paste nicht sinnvoll, da Einrückungen
verschwinden können! Diese sind in Python sehr wichtig. Daher ist beim E-Book links
oben immer die URL der Website, von der der Programmcode kopiert werden kann!
Hier kann auch nachgeschlagen werden, falls Code nicht vollständig sichtbar sein
sollte.
Danke für Ihre Unterstützung und viel Freude beim Lernen vom Python.
Alle Inhalte dieses E-Books, insbesondere Texte, Fotografien und Grafiken, sind urheberrechtlich
geschützt. Das Urheberrecht liegt, soweit nicht ausdrücklich anders gekennzeichnet, bei mir (Axel
Pratzner).
Inhaltsverzeichnis
1 Startseite
3 Python installieren
5 Python IDLE - Lernumgebung
8 Python Befehle ausführen
10 Programm ausführen + Command Line zum debuggen
12 Hilfefunktionen
16 Online-Editor zum schnellen Lernen
18 Text Editor Atom
21 Atom und Python
24 Python Grundlagen
26 Ausgabebefehl print()
28 Variablen/Strings in Python
31 Funktionen und Methoden für Strings
34 Leerzeichen am Anfang entfernen lstrip()
36 umschließende Leerzeichen entfernen strip()
38 Leerzeichen rechts entfernen rstrip()
40 Linksbündig ausgeben: ljust()
42 Zentrierte Ausgabe .center()
44 Rechtsbündig ausgeben: rjust()
46 Nullen am Anfang .zfill()
48 Umwandeln in Großschreibung upper()
49 Umwandeln in Kleinschreibung lower()
50 aggressive Kleinschreibung .casefold()
52 Erster Buchstaben in Großschreibung capitalize()
54 Anfangsbuchstaben in Großschreibung title()
55 Groß- u. Kleinschreibung vertauschen: swapcase()
56 Zeichen ersetzen .replace()
58 Vorkommen zählen .count()
60 Finden erstes Vorkommen .find()
61 String auf Bedingungen testen
63 Strings Aufteilen .split()
65 Endet-mit-Methode .endswith()
67 Beginnt-mit-Methode .startswith()
69 Tabs in Leerzeichen .expandtabs()
72 in Einzelteile zerlegen .partition()
74 Zusammenfügen join()
76 Operatoren für Strings
78 Rechnen mit Zahlen
81 Listen · viele Inhalte speichern
84 mit Listen arbeiten: Methoden
90 Übersicht aller Methoden des Datentyps Liste
91 Variablen sind Listen?
93 Datentyp Dictionary
97 Übersicht Methoden von dictionary
98 Tupel (Werte konstant speichern)
100 Übersicht Methoden von Tuple
102 Mengen managen set u. frozenset
107 Übersicht Methoden von set
108 input · Nutzerangaben anfordern
110 Kommentare nutzen
112 ausführbares Python-Programm erstellen
115 if-Bedingung
119 Zufallszahlen über random
122 Übung: Schmeichelprogramm
125 while-Schleife in Python
127 Übung: Zahlenraten-Spiel
130 for-Schleife in Python
133 Übung: Chatbot
139 range() · Listen erstellen
141 Übung: Lotto Simulator
143 Schleifenablauf beeinflussen: break & continue
145 Übung: Galgenmännchen
152 Funktionen in Python
156 Funktionen mit variabler Parameteranzahl
159 Rückgabewert bei Funktionen
164 eingebaute Funktionen
171 Module nutzen
173 Standardbibliothek/Module
175 Modul os: Betriebssystemfunktionalität
178 Modul datetime
185 Modul time
188 Modul calendar
190 tkinter - GUI erstellen
191 Tkinter importieren
192 Überblick über alle Steuerelemente
193 Label-Widget
195 Farben in tkinter
196 Schriftart und Schriftgröße
197 grid: Platzieren im Fenster
199 entry: 1-zeiliges Eingabefeld
200 Button/Schaltfläche erstellen
204 Cursorform ändern
205 Höhe und Breite setzen
206 Radiobutton
208 Checkbutton/Checkbox
211 LabelFrame · Gruppieren
213 Listbox: Inhalt zur Auswahl
215 Webbrowser über Python nutzen
217 URLLIB · Internetseiten auslesen
222 Bibliothek requests
227 Selenium Browser fernsteuern
230 matplotlib - 2D Diagramme
236 Natural Language Toolkit (NLTK)
239 Wordcloud mit Python erstellen
245 Tic-Tac-Toe Spiele-Tutorial
246 Spielfeld erstellen
247 Spielzug durch Spieler
249 Hauptroutine des Spiels erstellen
251 Spielfigur setzen
254 Spielende durch Gewinnen oder Unentschieden
258 Spielzugkontrolle
261 Dumme KI integrieren
262 Turtle-Modul von Python
266 Hauptprogramm __main__
268 Dateien auslesen
271 in Dateien schreiben
273 CSV Datei einlesen
276 Objektorientierte Programmierung Grundlagen (OOP)
280 Klassen in Python
282 Initialisieren der Klasse
285 Lösung Klasse erstellen
287 Instanz einer Klasse anlegen
290 Methoden in Klassen
297 Lösung Methoden in Klasse einbauen
300 Vererbung und Python
307 Attribute und Methoden in Klassen überschreiben
312 Lösung Aufgabe Vererbung
317 Vererbung weiterdenken
321 Variablen im Unterschied zu Eigenschaften in Klassen
325 Eigenschaften vor Zugriff absichern
334 Klassen auslagern
339 Python und Datenbanken
341 SQLite: grundsätzliche Vorgehensweise
345 Daten speichern: INSERT INTO
348 Viele Datensatz in Datenbank speichern
350 Datenbank auslesen
352 Datensätze ändern: UPDATE
354 Löschen: DELETE FROM
356 SQL Grundlagen lernen
361 SQLite3 Shell
364 CSV-Datei in SQlite3 Datenbank importieren
367 Pygame Einführung
376 Pygame installieren macOS
378 Formen zeichnen
383 Spiel Pong: Bewegung des Balls
391 Steuerung durch Spieler: Tastatur
401 Kollisions-Kontrolle · Aktion bei Schlägerberührung
407 Soundeffekte für unser Spiel und Hintergrundmusik
410 Koordinatensystem für Computerspiele
417 Spiel Breakout programmieren
420 Zeichnen der Mauersteine
423 Spielfeld mit Mauersteinen nach Vorgabe füllen
426 Breakout-Ball im Spiel zeichnen und bewegen
432 Kollision zwischen Ball und Mauerstein
438 Kontrolle: Spielende durch gewinnen
443 Spielerfigur (Schläger) einbauen und bewegen
448 Kollisionskontrolle Ball und Schläger
450 Kontrolle: Spielende durch verlieren
456 Grundgerüst für Pygame
462 Bilder und Grafiken anzeigen
468 Grafiken rotieren
478 Grafiken skalieren
484 Spielerfigur animieren
491 Space Invaders war gestern
494 eigene Spielerfigur einbauen
497 Spielerfigur steuern
501 Bewegung der Spielerfigur begrenzen
502 Gegner einbauen
506 Gegner automatisch bewegen
507 Gegner abschießen
510 Berechnung, wann Geschoss trifft
515 viele Gegner fürs Spiel
519 Kontrolle: Spiel gewonnen
520 aktuelle Punktestand anzeigen
521 Hintergrundmusik und Sounds einbauen
522 Raspberry Pi · Python Interpreter
523 Impressum
© https://www.python-lernen.de/ Seite 1
Galgenmännchen
Lotto-Simulator
einen Chatbot
Tic-Tac-Toe Spiel
Breakout
Dazu werden im Kurs Schritt für Schritt die Vorgehensweise beim Lernen von Programmieren
gezeigt. Es wird anhand von Beispiel-Code alle Befehle erklärt, wie man mit diesem Wissen
Programme schreibt. Beispielsweise wie aus einem Sprite-Sheet mit den einzelnen
Bewegungsstadien eine animierte Spielerfigur wird – in diesem Fall eine Honigbiene.
Und das fertige Ergebnis (sieht dann umgesetzt in Python + Pygame noch besser aus):
Funktionale Programmierung
Python ist eine gute Programmiersprache auch für Einsteiger, die bisher noch nicht mit
Programmieren und Programmiersprachen in Berührung gekommen sind.
Bei Python spricht man von einer Skriptsprache – ein erstelltes Programm wird interpretiert,
wenn es gestartet wird. Daher bekommt man erst dann Fehlermeldungen, wenn Fehler im
Python-Programm sind. Dazu aber später mehr. Die Sprache ist sehr einfach zu lernen und
durch die (erzwungene) saubere Erstellung von Code punktet die Sprache: Sie ist gut lesbar
und hat einen übersichtlichen kurzen Code. Daher ist Python sehr einfach zu lernen und ideal
als Einführung in eine Programmiersprache.
Unter Windows benötigen wir die Befehlszeile, die wir über die Suche und cmd.exe ( win + x -
Eingabeaufforderung) direkt starten können. Wir geben beim Cursor dann ein:
python - - version
Beim Mac und Linux öffnen wird die Kommandozeile ( CMD + Leertaste ) das Terminal
(terminal.app) und tippe dort ein:
Python --Version
bzw.
Python3 --Version
Auf dem Mac ist es durchaus möglich 2 verschiedene Versionen von Python installiert zu
haben. Normalerweise wird die alte Python 2.7 Version automatisch installiert sein. Sinnvoll
zum Lernen sind neue Versionen von Python >= 3.7
Python installieren
Die Installation ist sehr einfach – unter der Website https://www.python.org/ erhält man
Downloads für alle üblichen Betriebssystemen wie Windows, Linux/Unix, macOS und weitere.
Im ersten Schritt laden wir den Installer für das eigene Betriebssystem herunter und lassen
diesen dann Python installieren.
Beim Installer unter Windows auf jeden Fall "Add Python 3.7 to PATH" anklicken!
Hat man vergessen, beim Installer die Option zum automatischen Eintrag des Pfads unter
Windows anzuklicken, dann ist Handarbeit angesagt. Unter Windows muss der Pfad für die
Umgebungsvariablen eingestellt werden: Diesse finden man unter: Systemeigenschaften - >
© https://www.python-lernen.de/python-installieren.htm Seite 4
Reiter Erweitert -> Button Umgebungsvariablen -> Systemvariablen und dort Path auswählen
und Bearbeiten anklicken. Falls vorhanden, sollten bestehende Einträge erhalten werden! Man
erweitert den Pfad unter Windows mit einem Semikolon und den Pfad auf der eigenen
Festplatte, z.B. (;C:Python34)
Über eine Kommandozeile kann in Windows getestet werden, ob alles funktioniert. Über
Windowssuche "cmd" eingeben und in der "schwarzen Box" dann einfach python eingeben.
Hier sieht man die Version von Python und dessen Datum.
print('Hallo Welt')
Die Schreibweisen des Codes in alten Python-Versionen sieht anders aus, daher immer mit der
aktuellsten Version arbeiten.
Debugging
Windows: auch Startmenü klicken und IDLE eingeben – auswählen von IDLE (Python GUI)
macOS: Finder öffnen und auf Programm klicken. Dort unter Python auf das IDLE-Symbol
klicken. Oder über Spotlight-Suche ( CMD + Leertaste ) und IDLE eintragen und die IDLE-App
auswählen
Nach dem Start erscheint ein Fenster mit der Angabe der Python-Version:
Jetzt können direkt nach der Eingabeaufforderung (sprich den >>>) Befehle eingegeben
werden.
Über Alt + n bekommt man die nächsten Codeanweisung angezeigt, sofern vorhanden.
Wir erhalten ein weiteres leeres Fenster. In dieses können wir unser Python-Programm
schreiben.
Hier wird bereits der Vorteil sichtbar. Wir erhalten automatisch eine Code-Highlighting (eine
Einfärbung des Quellcodes).
Im folgenden Kapitel wird eine weitere Variante beschrieben, wie ein erstelltes Python-
Programm direkt über die Befehlszeile gestartet wird bzw. die Python Command Line genutzt
werden kann.
© https://www.python-lernen.de/python-befehle-ausfuehren.htm Seite 8
wir schreiben ein Python-Programm in einem Texteditor und rufen dieses dann auf oder
wir tippen unsere Python-Befehle direkt in die „Python Command Line“ und die Befehle werden
sofort und direkt ausgeführt.
Beides hat seine Berechtigung! Schauen wir uns beide Vorgehensweisen an.
bei Windows „cmd.exe“ über das Suchfeld eingeben und somit erhalten wir die Befehlszeile
beim Mac öffnen wir die Kommandozeile über CMD + Leertaste und dort das Terminal über
„terminal.app“
Haben wir die Befehlszeile des Betriebssystems, starten wir Python über python (unter
Umständen ist bei der Installation von 2 verschiedenen Versionen beim Mac als Start
python3 notwendig.
Nach den 3 „>>>“ geben wir unseren Python-Befehl ein und dieser wird direkt ausgeführt,
nachdem wir diesen mit Return bestätigen.
Danach können wir den nächsten Befehl eingeben. Werden Variablen definiert, liegen diese zur
weiteren Nutzung vor, solange nicht diese Instanz über exit() geschlossen wird.
Unsere bisherigen Befehle sind so natürlich nicht gespeichert und wenn wir diese wieder
ausführen lassen wollten, dann müssten wir alle Befehle in der entsprechenden Reihenfolge
wieder tippen. Diese Vorgehensweise ist also ungeschickt für sich wiederholende Aufgaben.
Da lohnt es sich dann immer über ein Python-Programm zu arbeiten, da in einer Datei
gespeichert ist, was wir im nächsten Schritt machen.
Wir wollen unser Python-Programm erstens öfters ausführen lassen und zweitens auch
ergänzen und erweitern. Dann hilft die „Python Command Line“ nicht weiter. Wir nutzen einen
Texteditor unserer Wahl und speichern unser Python-Programm unter einem Dateinamen mit
der Endung „.py“ ab.
Wir erstellen also eine Textdatei mit dem Dateinamen „hallo.py“ und folgendem Inhalt:
print("Hallo Welt")
Um unser Python-Programm nun ausführen zu lassen, rufen wir dieses über die
Kommandozeile auf. Wie man die Kommandozeile von seinem Betriebssystem erhält, ist oben
beschrieben.
Gehen Sie in der Befehlszeile in das Verzeichnis, in dem unser Python-Programm gespeichert
wurde. Dazu wechseln sie die Verzeichnisse mit „cd“, was für „change directory“ steht. Unter
Windows z.B. „cd c:/python-kurs.de/hallo.py“
Jetzt starten wir Python mit Leerzeichen und dem Dateinamen danach:
python hallo.py
python c:/python-lernen.de/hallo.py
Das Programm wird ausgeführt und wir erhalten die entsprechenden Ausgaben.
Wir haben die 2 Möglichkeiten kennen gelernt, wie wir Python-Code ausführen lassen
können:
Jetzt wäre eine Kombination aus beiden gut – gesagt getan und einfach möglich.
Das Python-Programm ausführen mit anschließender Python Command Line und Zugriff auf
alle Variablen und Möglichkeiten des ausgeführten Programms. Und das Ganze geht mit
einem kleinen Kniff.
Für Anfänger einfach für den Hinterkopf, damit man es später einsetzen kann bzw.
nachschlagen.
Wir haben ein kleines Python-Programm, dass „Hallo Welt“ ausgibt (was auch sonst) und eine
Variable speichert.
print("Hallo Welt")
nachricht = "alles in Ordnung"
Dieses Programm speichern wir mit dem Namen „hallowelt.py“ und starten es in der
Kommandozeile über „python hallowelt.py“.
Hallo Welt
Wenn wir aber jetzt nachsehen wollen, was in der Variablen mit dem Namen nachricht
steckt, haben wir anscheinend Pech. Theoretisch können wir unser Programm erweitern mit
dem typischen print() , speichern, ausführen lassen und später wieder diese Zeile
löschen. Diese war ja nur zum Debuggen da. ODER …
Oder wir kennen den Trick, beides zu bekommen. Die Ausführung des Programms und nach
Beendigung des Programms die Kommandozeile von Python mit den typischen 3
Größerzeichen:
Das Programm wurde nun ausgeführt. Nachdem das Programm alles abgearbeitet hat (eine
Ausgabe von „Hallo Welt“ ist ja nicht viel), landen wir direkt in der Python Kommando Zeile
und können diese wie gewohnt nutzen.
Jetzt können wir den Inhalt der Variablen mit dem Namen nachricht einfach direkt
abfragen. Einfach nach dem Prompt ">>>" den gewünschten Befehl tippen bzw. in diesem Fall
den gewünschten Variablennamen um den Inhalt der Variablen zu erhalten:
Hätten wir eine Funktion im Programm integriert, könnten wir auch diese nutzen.
Wir bauen uns eine Funktion ein, um Zahlen zu quadrieren (sprich eine Zahl wird mit sich
selber multipliziert).
print("Hallo Welt")
nachricht = "alles in Ordnung"
def quadrieren(zahl):
print(zahl*zahl)
Nachdem wir das Programm neu gestartet haben, können wir diese Funktion nun in unserer
Kommandozeile nutzen:
Hilfe-Funktionen in Python
Es gibt mehrere Möglichkeiten sich in Python Hilfen ausgeben zu lassen.
über IDLE
Es gibt eine Auswahl der verschiedenen Python-Versionen und als Sprache Englisch,
Französisch, Japanisch, Koreanisch, Chinesisch.
Beim Mac:
© https://www.python-lernen.de/python-help.htm Seite 14
file:///Library/Frameworks/Python.framework/
Versions/3.7/Resources/English.lproj/Documentation/index.html
Effektiv ist diese identisch mit der Online-Dokumentation – allerdings wird man Online immer
den aktuellen Stand bekommen.
In diesem Screenshot sieht man zusätzlich das Ausführen der Hilfe über die Konsole mit
help() .
>>> help()
If this is your first time using Python, you should definitely check out the tutorial on the Internet
at https://docs.python.org/3.7/tutorial/. Enter the name of any module, keyword, or topic to get
help on writing Python programs and using Python modules. To quit this help utility and return
to the interpreter, just type "quit".
To get a list of available modules, keywords, symbols, or topics, type "modules", "keywords",
"symbols", or "topics". Each module also comes with a one-line summary of what it does; to list
the modules whose name or summary contain a given string such as "spam", type "modules
spam".
Über die Python-Konsole können wir uns über die bereits standardmäßig in Python verfügbaren
Module informieren. Dazu einfach nach dem Prompt help> dann module eingeben.
help> modules
Please wait a moment while I gather a list of all available modules...
© https://www.python-lernen.de/python-help.htm Seite 15
Das Tolle an diesem Online-Python-Editor ist, dass dieser einen ideal beim Lernen unterstützt.
Klar ist, dass dieses Kapitel zum Vorstellen des Online-Lern-Editors vor den Kapiteln zum
Lernen von Python etwas problematisch ist, da wir ja noch kein Python programmieren
können. Aber einfach einmal ansehen und im Zweifel später, wenn nicht alles klar geworden ist
(was logischerweise normal wäre), nochmals dieses Kapitel lesen.
Wir erhalten folgendes unscheinbares Fenster. Hier nicht täuschen lassen – die Möglichkeiten
sind klasse und beschleunigt das Verständnis zum Lernen von Python!
Jetzt gebe ich den ersten Python Code ein – das typische "Hallo Welt" Ausgabe Programm:
Rechts sehen wir nun die Ausgabe, die wir auch erhalten würden, wenn wir Python auf dem
eigenen Computer installieren. Das ist schon mal ganz nett, aber das besondere kommt erst
noch!
Sofort sehe ich rechts im Bereich "Global frame", die vergebenen Namen für unsere
verschiedenen Variablen und Datenstrukturen.
Zusätzlich weiter rechts, in Gelb unterlegt, noch den Inhalt von "list" und "tuple". Hier sieht man
auch, dass Python immer bei 0 anfängt zu zählen.
Und hier hört der Spaß noch lange nicht auf. Wenn wir dann in das Kapitel zur
objektorientierten Programmierung kommen, hilft auch hier der Online-Editor schnell weiter,
um ein Verständnis aufzubauen. Ich möchte nur den rechten Ausgabeteil für OOP anzeigen.
So gut wie alle Beispiele aus diesem Kurs können direkt im Online-Editor ausprobiert werden.
Viel Spaß beim schnellen Lernen.
© https://www.python-lernen.de/text-editor-atom.htm Seite 18
Text-Editor Atom
Der Text-Editor Atom hat viele Komfortmerkmale zum Programmieren in Python von Haus aus
und bietet noch deutlich mehr durch seine Erweiterbarkeit. Er ist für die Plattformen Windows,
Mac OS X, Unix/X verfügbar und ist Open Source (sprich es entstehen keine Kosten). Er wurde
von den GitHub Leuten entwickelt und steht seit 2014 unter der freien MIT-Lizenz zur
Verfügung.
Nach der Installation (nachdem alles in die Rakete geladen wurde) sieht der Editor eher
unscheinbar aus. Was ein großer Vorteil ist: wir haben eine aufgeräumte Oberfläche, die nicht
vom eigentlichen ablenkt – dem programmieren.
Jetzt können wir uns im frisch gestarteten Editor über das Menü „File“ eine neue Datei „New
File“ erstellen.
Natürlich testen wir mit dem typischen "Hallo Welt"-Programm. Erst durch das Speichern ist
dem Editor klar, dass wir in Python programmieren und die farbige Syntaxhervorhebung wird
automatisch aktiviert. Will man die Syntaxhervorhebung ohne zu speichern aktivieren, kann
man im Fußbereich rechts (links neben dem Logo von GitHub) die gewünschte
Programmiersprache einstellen.
© https://www.python-lernen.de/text-editor-atom.htm Seite 19
Python-Programm in Atom
Nutzen wir Variablen in unserem Code, werden auch diese uns vorgeschlagen. Im folgenden
Beispiel sieht man das schön anhand des unkreativen Variablennamens "variablenname".
Dies geschieht im ersten Menüpunkt „settings“ bzw. „Preferences“ (Shortcut CMD und + beim
Mac bzw. Strg und + bei Windows) über den Unterpunkt „Themes“. Hier kann dann für die UI
(sprich Benutzeroberfläche) bzw. für das Syntax-Theme (Code) etwas nach dem eigenen
Geschmack ausgewählt werden. Ist nichts Passendes da, können online unzählige Themen
nachinstalliert werden.
Im folgenden Kapitel schauen wir uns an, wie wir den Editor noch wesentlich besser für das
Programmieren mit Python ausrüsten können.
© https://www.python-lernen.de/text-editor-atom-plugins-python.htm Seite 21
Das gewöhnen wir Atom direkt ab und packen ein Plug-in direkt für die Python
Codevervollständigung dazu.
Settings -> Packages -> in den “Core Packages” die folgenden 2 Pakete abschalten
Ab jetzt haben wir mehr Komfort und bekommen beim Tippen der ersten Buchstaben
entsprechende Befehle vorgeschlagen.
Nach dem Installieren des Plug-ins zur Sicherheit den Editor neu starten und dann einfach den
Shortcut für den Aufruf ausprobieren:
Mit CMD + SHIFT + i kann der Aufruf noch getunt werden. Beim Mac wird (je nach Version)
noch Python 2.7 standardmäßig aufgerufen. Oder man hat die Version 3.x laufen und möchte
mit einer alten 2.7 Version testen – dann ist die Vorgehensweise wie folgend beschrieben.
Über den Python-Code bekommen wir den Pfad unserer Python-Installation direkt angezeigt:
import sys
print(sys.executable)
/Library/Frameworks/Python.framework/Versions/3.7/bin/python3
Speichern als „profile“, dass dann aufgerufen werden kann. Beim Mac mit der
Tastenkombination CMD + SHIFT + K und Windows Shift + Ctrl + alt + b
Sollte es Probleme mit dem Ausführen des Packages geben, weil Atom keine Pfade vorliegen
hat, dann Atom über die console/terminal starten:
atom .
Python Grundlagen
Zum Lernen einer Programmiersprache (und bevor man irgendwelche coolen Spiele
programmieren kann), benötigt man ein paar Grundlagen. Dies ist das Grundlagen-Kapitel.
Grundsätzlich zeichnen sich Programmiersprachen durch das EVA-Prinzip aus. Dabei steht
jeder Buchstabe für eine wichtige Möglichkeit und beschreibt die Grundprinzipien der
Datenverarbeitung:
E: Eingabe
V: Verarbeitung
A: Ausgabe
In diesem Grundlagen-Kapitel drehen wir die Reihenfolge um – sprich wir machen EVA und
begrüßen Python und tolle Möglichkeiten mit einer schnellen und einfach zu erlernenden
Programmiersprache.
Ausgabe in Python
Wir schauen uns als Erstes die Ausgabe an – sprich wir lassen etwas über print auf dem
Bildschirm ausgeben.
Verarbeitung
Natürlich möchten wir nicht nur einen bestehenden Inhalt ausgeben, sondern diesen auch
verarbeiten können. Dazu helfen mathematische Funktionen – großes Wort, gemeint ist damit
einfach Grundrechenarten wie z.B. addieren.
Zum Verarbeiten müssen wir den Text „zwischenspeichern“ können. Dazu lernen wir Variablen,
Listen und Tupel kennen.
Eingabe
Und ohne eine Nutzereingabe macht es viel weniger Spaß. Daher sollen in unser Programm
auch Inhalte von außen kommen können – sprich wir fragen den Benutzer und verarbeiten
dann diese Eingaben weiter. Es kann sehr einfach aussehen, dass das Eingegebene einfach
wieder auf dem Bildschirm ausgegeben wird, oder damit gerechnet wird.
Das sind unsere Grundlagen. In allen Programmiersprachen immer dasselbe – nur der
Befehlsaufbau unterscheidet sich.
print('Hallo Welt');
Die in der Klammer angegebenen Anführungszeichen dienen zum Umschließen der Ausgabe
und werden nicht mit ausgegeben.
Mit der Funktion print() können wir auch den Inhalt von Variablen (mehr zu Variablen im
folgenden Kapitel) ausgeben lassen. Dazu wird einfach der Variablennamen in die Klammern
geschrieben (auf jeden Fall ohne Anführungszeichen, sonst wird der Variablenname einfach
als Zeichenkette ausgegeben und nicht der Inhalt des Strings).
print(vorname)
Ist der Variable noch kein Inhalt zugewiesen, wird eine Fehlermeldung (Traceback)
ausgegeben: NameError: name 'vorname' is not defined
Daher erst einmal den Inhalt der Variable vor der Ausgabe über print() festlegen:
Es gibt noch weitere Möglichkeiten, eine Leerzeile auszugeben. Dazu benötigen wir aber erst
unseren Sonderfall im sofort folgenden Abschnitt!
Sonderfall Backslash
Enthält eine Variable ein Backslash, dann ist spannend, was die Ausgabe daraus macht.
Natürlich fragt man sich, wann man überhaupt einen Backslash in einer Variablen haben sollte.
Nehmen wir an, wir wollen einen Pfadnamen von der Festplatte in einer Variablen speichern.
Dann wäre die Schreibweise
pfad = 'C:\niedlicherverzeichnisname'
pfad = "C:\niedlicherverzeichnisname"
print(pfad)
Nun erhalten wir eine Ausgabe über 2 Zeilen umgebrochen ohne den Backslash und vor wurde
allem unser "niedlich" zu "iedlich":
© https://www.python-lernen.de/ausgabebefehl-print.htm Seite 27
c:
iedlicherverzeichnisname
Was ist passiert. Den Backslash haben wir bei den Variablen bereits kennengelernt. Hier war er
dafür da, bestimmte Zeichen zu maskieren, damit diese überhaupt ausgegeben werden
können. Unser Backslash hat also mehr als eine Bedeutung. Wollen wir einen Backslash
ausgeben, müssen wir den Backslash mit einem Backslash maskieren:
pfad = "C:\\niedlicherverzeichnisname"
Aber was ist nun wirklich im Hintergrund passiert? Es gibt sogenannte Steuersequenzen, die
die Ausgabe beeinflussen. Und genau so eine Steuersequenz haben wir mit \n versehentlich
erwischt.
Wollen wir also eine Leerzeile gezielt ausgeben lassen, dann einfach 2-mal den Zeilenumbruch
\n\n in der Anweisung print nutzen.
print(r"C:\niedlicherverzeichnisname")
print(rpfad)
Nun haben wir da keine eindeutige Angabe und bekommen eine Fehlermeldung!
print("""Hallo
Welt
– in 3 Zeilen""")
© https://www.python-lernen.de/variablen-einsetzen.htm Seite 28
Unser virtueller Schrank hat beliebig viele Schubladen. Jetzt müssen wir natürlich irgendwie
in Python sagen, welche Schublade wir nutzen möchten. Um eine bestimmte Schublade
auszuwählen, ist die Variante "dritte Schublade von rechts und zweite von oben" ein wenig
unhandlich.
Daher benötigen wir ein System, das handlicher ist und verständlich. Daher können wir
unseren Schubladen Namen geben. So können wir Beispielsweise eine Schublade beschriften
mit "vorname". Somit wissen wir, dass wir in dieser Schublade einen Vornamen finden.
Bei der Vergabe von Namen für unsere Variablen gibt es folgende Kriterien:
keine Leerzeichen
Um nun die Schublade zu nutzen, also etwas in der Schublade (Variablen) abzulegen wird
dem Variablennamen über ein Gleichheitszeichen ein Inhalt zugewiesen.
vorname = 'Axel'
Wichtig ist, dass der Inhalt (hier der Name 'Axel') mit einfachen Anführungszeichen
umschlossen wird (das neben der Enter-Taste – NICHT "accent circonflexe/grave"!).
vorname = "Axel"
Dieses Umschließen ist aus zwei Gründen wichtig, da der Variableninhalt auch aus mehreren
Worten bestehen kann. Somit umschließen unsere einfachen Anführungszeichen unseren
Inhalt. Würde wir ganz auf Anführungszeichen verzichten, würden wir einer Variablen den
Inhalt der zweiten Variablen zuweisen. Technisch funktioniert dies problemlos – nur wenn es
nicht gewünscht ist, dann kommen irritierende Ergebnisse!
vorname = Axel
Das klappt nicht. Wir bekommen eine Fehlermeldung "NameError: name 'Axel' is not defined".
Warum? Hier versuchen wir der Variablen vorname den Inhalt der (jetzt kommt es) Variable
mit dem Namen "Axel" zuzuweisen. Daher kommt es zu dieser Fehlermeldung.
Funktionieren würde (Über den Sinn kann man sich Gedanken machen):
Axel = "Test"
vorname = Axel
vorname = ''
vorname = ""
Was passiert aber, wenn wir das einfache Anführungszeichen als Inhalt benötigen? Also
Wörter mit Apostroph – im Deutschen wird das Hochkomma auch Apostroph genannt und
wird zur kennzeichnet beispielsweise den Genitiv von Eigennamen oder Auslassungen (sorry
für den Ausflug in die Grammatik der deutschen Sprache). Als Beispiel dafür "Ku’damm für
Kurfürstendamm". Wollten wir nun aber den "Ku'damm" in einer Variablen nutzen:
strasse = 'Ku'damm'
Dann ergibt diese Nutzung Probleme! Warum. Python schaut nach dem Anfangs-
Anführungszeichen und startet dann, alles danach bis zum nächsten einfachen
Anführungszeichen dies der Variablen zuzuweisen. In unserem Fall wäre das dann "Ku". Mit
dem Rest ist nun Python komplett verwirrt und weiß nicht mehr was tun und wirft mit einer
Fehlermeldung nach uns: "SyntaxError: invalid syntax"
Um nun keine Katastrophe mit dem Apostroph zu erleben, müssen wir diesen "tarnen". Hier
spricht man bei Programmiersprachen von "maskieren". Vor diesem Zeichen wird ein
Backslash gepackt und die Welt ist für Python wieder in Ordnung
strasse = 'Ku\'damm'
Im Zusammenhang mit Variablen fallen Begriffe wie "string". Dahinter verbirgt sich, dass eine
Zeichenkette (sprich "string") genutzt wird. Unterschieden werden z.B. Ganzzahlen, die dann
als "int" (ausgeschrieben Integer bzw. Ganzzahl").
meine_variable = "Inhalt"
Sprechende Variablennamen
Ein Variablenname sollte sprechend, also erkennbar sein, was in der Variablen gespeichert
ist. Früher hat man lustig Variablennamen wie „x1“ oder „i3“ vergeben. Spätestens nach 2
Wochen wusste selbst der Programmierer des Codes nicht mehr so genau, was hinter der
Variablen steckt (sobald das Programm ein wenig komplexer war als ein 3-Zeiler). Daher ist
es sinnvoll, kurze aussagekräftige Variablennamen zu vergeben.
Wenn der Inhalt unserer Variablen über mehrere Zeilen gehen soll, weil wir z.B. Macbeths
Hexenszene in einer Variablen speichern wollen, dann klappt folgende Variante NICHT:
# FUNKTIONIERT NICHT!
macbethtext = "Schön ist häßlich, häßlich schön.
Wir weichen wie Wolken und Windeswehn."
Hier kommen nun 3 Anführungszeichen hintereinander zum Einsatz. Dadurch können wir
über beliebig viele Zeilen den Inhalt der Variable schreiben:
Wobei sowohl doppelte wir einfache Anführungszeichen funktionieren (nur müssen die
gewählten Anführungszeichen sowohl am Anfang wie am Ende genutzt werden). Das letzte
Beispiel mit einfachen Anführungszeichen:
Über die Funktion print() erhalten wir den abgelegten Inhalt einer Variablen angezeigt.
kursname = 'Python-lernen.de'
print(kursname)
Es muss allerdings nicht immer einer Funktion weitere Werte und Anweisungen in der
Klammer mit übergeben werden. Wird print() einfach mit einer leeren Klammer
aufgerufen, dann erhalten wir als Ergebnis eine Leerzeile ausgegeben.
Schauen wir uns eine andere Funktion neben print() an. Zum Bestimmen der Länge eines
Strings gibt es die Funktion len(x) . Als Information erhalten wir hier die Anzahl der
enthaltenen Zeichen. Bei len handelt es sich um die Abkürzung des englischen Worts
„length“. Allerdings müssen wir irgendwas mit dieser Information machen. Lassen wir uns
diese ausgeben:
kursname = 'Python-lernen.de'
print(len(kursname))
Funktionen sind unabhängig. Wir können die Funktionen nicht nur für Strings nutzen!
Funktionen sind soweit einfach verständlich. Was aber sind Methoden und was können wir
damit bei Variablen anstellen?
objektname.aktion
kursname = 'www.Python-lernen.de'
kursname.lower()
© https://www.python-lernen.de/unterschied-methoden-funktionen.htm Seite 32
Wer sich jetzt denkt, das fühlt sich doch an wie eine Funktion, die einfach alles in
Kleinbuchstaben umwandelt, liegt nicht wirklich falsch. Es ist einfach eine andere Sichtweise
– sprich die objektorientierte Sichtweise. Und somit wird die objektorientierte Schreibweise
notwendig.
Die wirkliche Kunst liegt darin zu wissen, welche Objekte welche Möglichkeiten (sprich
Methoden) bieten.
Diese Hilfe können wir über die Anweisung help(str) anfordern für unsere Strings (was
unsere Variablen sind). Hier kommt dann ein sehr umfangreicher Text:
>>> help(str)
class str(object)
| str(object='') -> str
| str(bytes_or_buffer[, encoding[, errors]]) -> str
|
| Create a new string object from the given object. If encoding or
| errors is specified, then the object must expose a data buffer
| that will be decoded using the given encoding and error handler.
| Otherwise, returns the result of object.__str__() (if defined)
| or repr(object).
| encoding defaults to sys.getdefaultencoding().
| errors defaults to 'strict'.
|
| Methods defined here:
...
Zum Scrollen die Pfeiltasten nutzen, zum Beenden der Hilfe einfach „q“ drücken.
Möchte man eine kürzere Übersicht, was uns Strings (sprich „str“) bieten, dann können wir
diese über dir(str) erhalten:
Alles ohne Unterstriche sind Methoden, die für String-Objekte zur Verfügung stehen. Hier
taucht unser lower aus dem letzten Beispiel auf.
Und wollen wir nur genauere Hilfe zu der Methode lower dann bekommen wir diese über
die Anweisung help(str.lower)
© https://www.python-lernen.de/unterschied-methoden-funktionen.htm Seite 33
Help on method_descriptor:
lower(self, /)
Return a copy of the string converted to lowercase.
Das war jetzt ein größerer Brocken. Wer unseren oberen Code einmal getestet hat, wird sich
wundern, dass keine Ausgabe in Kleinschreibung erfolgt ist. Das ist auch korrekt so. Die
Methode lower() wandelt nur in Kleinschreibung um. Wollen wir eine Ausgabe, benötigen
wir wie gewohnt unsere print() -Anweisung:
kursname = 'www.Python-lernen.de'
print(kursname.lower())
Am Rande bemerkt: Unser Inhalt der Variable „kursname“ wird nicht verändert! Diese bleibt
unberührt. Einfach mal folgenden Code testen:
kursname = 'www.Python-lernen.de'
print(kursname.lower())
print(kursname)
Zusammengefasst:
Unterschied zwischen Funktionen und Methoden
Funktionen können direkt über ihren Namen aufgerufen werden – Methoden dagegen
benötigen immer ihr Objekt.
Die Schreibweise:
Funktionen: funktionsname()
Methoden: objekt.methode()
Funktionen sind unabhängig. Einer Funktion kann beliebiges übergeben werden, mit dem
dann weitergearbeitet wird. Methoden sind festgelegt – sprich jedes Objekt verfügt über
bestimmte Möglichkeiten (sprich Methoden). Die Kunst ist nur zu wissen, was es an
Methoden bereits „standardmäßig“ gibt.
Befehlsaufbau:
str.lstrip([Zeichen])
Als Ergebnis erhalten wir einen linksbündigen Text ohne führende Leerzeichen:
Python rocks
Die Leerzeichen rechts bleiben bestehen. Wenn wir einen zusätzlichen Text ausgeben lassen,
sieht man das:
Python 3 rocks
Es ist möglich mehrere Zeichen einzugeben, die entfernt werden sollen - auch das
Leerzeichen!
© https://www.python-lernen.de/string-methode-lstrip.htm Seite 35
Es werden also folgende Zeichen entfernt: Zahlen von 1 bis 9 und Leerzeichen:
Python 3 rocks
Alles am Anfang wird entfernt, bis die Methode auf das Erste nicht zu entfernende Zeichen
stößt. Daher bleibt die 3 nach Python mitten im Text stehen!
Befehlsaufbau:
str.strip([Zeichen])
Der Parameter ist optional (daher die eckigen Klammern). Der Parameter steht für das Zeichen
bzw. die Zeichen, die am Anfang und Ende entfernt werden sollen. Wird hier nichts angegeben,
wird das Leerzeichen (der übliche Übeltäter) entfernt. Schauen wir es uns im Beispiel an:
Alle Leerzeichen um unseren Beispieltext (eine URL, in der es einfach auch Leerzeichen geben
darf) sind entfernt.
https://www.python-lernen.de
Kommt unser Text aus einer Aufzählung z.B. heraus, können wir die Zahlen und den
Aufzählungspunkt auch entfernen:
.) https://www.python-lernen.de
Wir wollen auch keine Punkte, Klammern und Leerzeichen. Also geben wir alle unerwünschten
Zeichen als Parameter an:
https://www.python-lernen.de
© https://www.python-lernen.de/string-methode-strip.htm Seite 37
Auch wenn wir alle Punkte entfernen, dann bezieht sich das nur auf die Punkte am Anfang und
Ende! Die strip() -Methode hört sofort mit dem entfernen auf, sobald das erste erwünschte
Zeichen kommt. Sprich unsere Punkte innerhalb der URL bleiben erhalten. Das wäre anders,
wenn wir einen deutschen Satz mit einem Punkt am Ende hätten. Dieser Punkt würde bei
unserem Beispielaufbau der strip() -Methode zum Opfer fallen.
Langer Rede kurzer Sinn: diese Methode wird überaus häufig in der Praxis genutzt.
Befehlsaufbau:
str.rstrip([Zeichen])
Für die bessere Sichtbarkeit des Effekts lassen wir einen zusätzlichen Text ausgeben. Wir
erhalten folgende Ausgabe:
Es werden also folgende Zeichen entfernt: Zahlen von 1 bis 9, Fragezeichen, Leerzeichen und
„XYZ“ (aber nur in Großschreibung):
Alles am rechten Ende wird entfernt, bis die Methode auf das Erste nicht zu entfernende
Zeichen stößt. Daher bleibt die 3 nach Python mitten im Text stehen!
Die rstrip() -Methode von Python entfernt standardmäßig alle Arten von nachgestellten
Leerzeichen. Dazu gehören nicht Zeilenumbruch und neue Zeilen, die über den Steuercode \r\n
übertragen werden.
Das Ergebnis:
Python rocks
Möchte man gezielt einen bestimmten Zeilenumbruch nur entfernen, muss dieser als
Parameter mit Übergeben werden:
Als Ergebnis werden alle Umbruch (\n) und Leerzeichen gelöscht. Ein Umbruch (\r) bleibt
erhalten:
Python rocks
, damit sichtbar wird, was gelöscht wurde
Sollen alle Zeilenumbruch und Leerzeichen entfernt werden, müssen alle 3 Angaben in
rstrip('\n \r') gemacht werden! Dabei ist die Reihenfolge egal. Es funktioniert genauso:
rstrip(' \r\n')
Das Ergebnis:
str.ljust(Breite[, Füllzeichen])
Schauen wir unser erstes Beispielprogramm an. Wir lassen uns das Wort „Vier“ ausgeben,
dass 4 Buchstaben breit ist. Es bekommt einen Platz von 10 über ljust() :
inhalt = "Vier"
ausgabe = inhalt.ljust(10)
print(ausgabe)
In der Ausgabe sieht man nicht direkt die Auswirkung von ljust() :
Vier
Würde danach gleich ein Text kommen, wäre die Auswirkung sichtbar:
inhalt = "Vier"
ausgabe = inhalt.ljust(10)
print(ausgabe, "mehr Text")
Und nun ist der Abstand 6 Zeichen – 4 Zeichen von unserem Beispielwort minus den 10
vorgegebenen Zeichen ergibt 6 Leerzeichen:
Wir können bei der Methode noch die Füllzeichen mitgeben und damit wird das Auszählen der
Abstände einfacher:
inhalt = "Vier"
ausgabe = inhalt.ljust(10, '.')
print(ausgabe, "mehr Text")
Hier taucht ein Leerzeichen zwischen unserem weiteren Text und den 10 Zeichen von
ljust() auf. Durch eine Verknüpfung mit „+“ wird dies nicht mehr erscheinen:
inhalt = "Vier"
ausgabe = inhalt.ljust(10, '.')
print(ausgabe + "mehr Text")
Allerdings hat der Inhalt Vorrang vor Breitenangabe. Ist der Inhalt breiter als die mitgegebene
Breite, wird der komplette Inhalt gefolgt von einem Leerzeichen ausgegeben:
© https://www.python-lernen.de/string-methode-ljust.htm Seite 41
inhalt = "Vier"
ausgabe = inhalt.ljust(2, '.')
print(ausgabe, "mehr Text")
Beispielcode:
inhalt = "mittig"
print( inhalt.center(12) )
mittig
Besser sichtbar ist die Arbeitsweise von zentrierten Ausgaben, wenn wir ein anderes
Füllzeichen als das Leerzeichen wählen:
Beispielcode:
inhalt = "mittig"
print( inhalt.center(12,"^") )
^^^mittig^^^
Unser Beispielwort ist 6 Zeichen lang und wir wollen es zentriert auf 12 Zeichen ausgeben.
Dann kommen 3 Füllzeichen rechts und 3 Füllzeichen links neben unserem Beispielwort.
Geht es nicht so schön auf, dass wir die gleiche Anzahl von Füllzeichen links wie rechts haben,
wird auf einer Seite ein Füllzeichen mehr ausgegeben:
inhalt = "mittig"
print( inhalt.center(11,"^") )
^^^mittig^^
Lustigerweise ist die Verteilung, ob das Füllzeichen rechts oder links von unserem Text mehr
ausgegeben wird, abhängig davon, ob wir eine gerade oder ungerade Anzahl von Zeichen bei
unserem Text haben. Einfach einmal probieren.
inhalt = "Mitte"
print( inhalt.center(8,"^") )
^Mitte^^
© https://www.python-lernen.de/string-methode-center.htm Seite 43
inhalt = "Mitte"
print(inhalt.center(2,"^"))
Unser Beispielwort „Mitte“ benötigt mindestens 5 Zeichen, bekommt aber im Beispiel nur 2 zur
Verfügung gestellt. Macht nichts, da wir die Ausgabe des kompletten Beispielwortes erhalten,
was allerdings nicht zentriert werden kann.
Mitte
str.rjust(Breite[, Füllzeichen])
Schauen wir unser erstes Beispielprogramm an. Wir lassen uns das Wort „Vier“ ausgeben,
dass 4 Buchstaben breit ist. Es bekommt einen Platz von 10 über rjust() :
inhalt = "Vier"
ausgabe = inhalt.rjust(10)
print(ausgabe)
In der Ausgabe sieht man direkt die Auswirkung von rjust() . Es werden 6 Leerzeichen vor
dem Wort „Vier“ ausgegeben:
Vier
inhalt = "Vier"
ausgabe = inhalt.rjust(10)
print(ausgabe, ", weiterer Text")
Und nun der Abstand von 6 Zeichen (4 Zeichen von unserem Beispielwort minus den 10
vorgegebenen Zeichen ergibt 6 Leerzeichen):
Hier fällt das Leerzeichen vor unserem „weiteren Text“, sprich vor dem Komma auf. Durch
eine Verknüpfung mit „+“ wird dies nicht mehr erscheinen:
inhalt = "Vier"
ausgabe = inhalt.rjust(10)
print(ausgabe + ", weiterer Text")
Ergebnis:
Wir können bei der Methode noch die Füllzeichen mitgeben und damit wird das Auszählen der
Abstände einfacher:
inhalt = "Vier"
ausgabe = inhalt.rjust(10, '.')
print(ausgabe + ", weiterer Text")
Allerdings hat der Inhalt Vorrang vor Breitenangabe. Ist der Inhalt breiter als die mitgegebene
Breite, wird der komplette Inhalt gefolgt von einem Leerzeichen ausgegeben:
inhalt = "Vier"
ausgabe = inhalt.rjust(2, '.')
print(ausgabe + ", weiterer Text")
Dabei steht das „z“ bei der Methode für „Zero“ – also mit „Nullen füllen“ wenn man den
englischen Begriff übersetzt.
Beispiel:
text = "20"
print(text.zfill(8))
00000020
Wird der Parameter vergessen, erhält man als Fehlermeldung: „TypeError: zfill() takes exactly
one argument (0 given)“
Es muss auch ein String übergeben werden! Man denkt zwar beim Auffüllen mit Nullen immer
an Zahlen, allerdings werden wir auch dann eine Fehlermeldung erhalten, wenn wir eine Zahl
anstelle eines Strings übergeben würden ( zahl = 20 ). Als Fehlermeldung kommt dann:
„AttributeError: 'int' object has no attribute 'zfill'“
Ergebnis:
text = "-123"
print(text.zfill(8))
-0000123
aber das Zeichen angeben, mit dem der String aufgefüllt werden soll. Hierzu folgendes
Beispiel:
text = "-123"
print(text.rjust(8,"0"))
0000-123
casefold() ändert unter Umständen auch Zeichenfolgen. Was geht da vor. Normalerweise
wird man sich denken, zu jedem Großbuchstaben gibt es einen Kleinbuchstaben. Aus einem
großen „A“ wird einfach ein kleines „a“. Aber was ist beispielsweise mit „ß“? Schauen wir uns
an, was casefold() uns daraus bastelt:
Originaltext:
Inhalt mit Umlauten: ÄÖÜß
Aus einem „ß“ wir korrekt ein „ss“. Hier werden als nationale Besonderheiten berücksichtigt.
Wer es genau benötigt, kann sich die Zusammenstellung beim Unicode-Konsortium
herunterladen (siehe https://unicode.org/faq/casemap_charprop.html unter CaseFolding.txt).
Hier als kleine Übung wofür man casefold() sinnvoll einsetzen können. Es bietet uns die
Möglichkeit zur Normalisierung von Text und wir können von einem vorliegenden Text
überprüfen, ob dieser ein Palindrom ist. Was ist ein Palindrom? Für alle, bei denen der
Schulunterricht schon ein paar Tage zurückliegt: Übersetzt bedeutet Palindrom „rückwärts
laufend“. So ist der Name „Otto“ und „Hannah“ rückwärts geschrieben exakt das Gleiche.
Erst selber ein Python-Programm erstellen und dann die Lösung ansehen. Wir benötigen dazu
auch die Funktion reversed(str) , .join() und list() , die uns die Reihenfolge
umdreht.
text = "Rentner"
text = text.casefold()
rueckwarts = reversed(text)
print(text)
print(rueckwarts)
Als Objekt können wir es nicht mit einem String vergleichen. Also erstellen wir über .join
einen String.
text = "Rentner"
text = text.casefold()
rueckwarts = ''.join (reversed(text))
text = "Rentner"
text = text.casefold()
rueckwarts = ''.join (reversed(text))
if text == rueckwarts:
print(text, " ist ein Palindrom")
else:
print("KEIN Palindrom")
Die Schreibweise vom Text ist gleichgültig. Alle Zeichen, egal wie diese im Ursprungstext
geschrieben wurden, werden bis auf das erste Zeichen in Kleinbuchstaben umgesetzt. Nur der
erste Buchstabe wird als Großbuchstaben ausgegeben:
Probieren wir es bei Zahlen und Vorzeichen. Hier haben wir keinen Unterschied bei Groß- und
Kleinschreibung. Das wäre jetzt nicht weiter Erwähnenswert, wenn es nicht den Buchstaben „ß“
(Eszett) gäbe. Aber der Reihe nach. Schauen wir uns das Verhalten von capitalize() bei
Zahlen und Vorzeichen an:
123 text
+123 text
© https://www.python-lernen.de/string-methode-capitalize.htm Seite 53
Ss text
Wobei das Großes Eszett es seit 2017 auch offiziell als Großbuchstaben gibt! Und dieses hat
definitiv nicht die Umsetzung in „Ss“ - wobei hier schätzungsweise wieder nationale
Sonderwege gibt. Vielleicht ist es bei den Schweizern oder Österreichern in dieser Form üblich.
Äöü text
Bisher ist mir keine direkte Anwendung beim Programmieren unter die Finger gekommen. Aber
wer weiß, irgendwann und irgendwer wird die Methode capitalize() schon sinnvoll
benutzen können.
Das könnte man bei „normalen“ Vor- und Nachnamen machen, aber sobald ein „von“ oder
„van“ dazukommt, läuft es schief.
ausgabetext = "Der Preis für 2 Socken beträgt 5 DM und 5 Paar kosten 10 DM"
print(ausgabetext)
ausgabetext = ausgabetext.replace("DM", "Euro")
print("Nach dem Austauschen über replace():")
print(ausgabetext)
ausgabetext = "Der Preis für 2 Socken beträgt 2 DM und 2 Paar kosten 3.50 DM"
ausgabetext = ausgabetext.replace("DM", "Euro")
ausgabetext = ausgabetext.replace("2", "zwei", 2)
print("Nach dem Austauschen über replace():")
print(ausgabetext)
Der Preis für zwei Socken beträgt zwei Euro und 2 Paar kosten 3.50 Euro
Als Rückmeldung erhält man „3“. Der Buchstabe „i“ kommt also 3-mal in unserem String vor.
Wir können auch nach mehr als einem Buchstaben suchen. Natürlich gehen ganze Wörter oder
auch Wortteile wie z.B. „in“.
Bei dem Wort „Inhalt“ haben wir ein weiteres „in“, das allerdings mit Großschreibung beginnt.
Mit der Großschreibung wird es allerdings nicht gefunden, sprich das „In“ von dem Wort
„Inhalt“ wurde nicht gefunden und somit auch nicht mitgezählt. Es gibt bei der Methode
.count() keinen optionalen Parameter, aber ein die entsprechende Methode zur
Umwandlung in Kleinbuchstaben haben wir bereits kennengelernt, mit der wir dies erreichen.
Es wird dann nur der Teil des Strings mit dem Inhalt „Hier kommt ein“ ausgewertet und dort
wird dann einmal der gesuchte Teilstring „in“ gefunden im letzten Wort „ein“.
© https://www.python-lernen.de/methode-string-count.htm Seite 59
Weitere Nutzungsmöglichkeiten
Die Methode .count() kann genauso bei Listen eingesetzt werden!
© https://www.python-lernen.de/methode-string-find.htm Seite 60
Die Zählung beginnt bei 0, daher ist die dritte Stelle dann die Nummer 2.
Wollen wir das nächste Vorkommen von „e“ finden, können wir den Start mitgeben als weitere
Parameter:
11
Bereiche können auch definiert werden. Wird die letzte Zahl negativ angegeben, erfolgt die
Zählung von hinten:
Im Folgenden die Übersicht aller Methoden des Datentyp Strings und is…:
Methode Beschreibung
string.isalnum() Überprüft auf alphanumerische Zeichen (a-zA-Z0-9). Leerzeichen ist kein alphanumerisches
Zeichen!
string.isalpha() Überprüft auf alphabetische Zeichen (a-zA-Z). Leerzeichen ist kein alphanumerisches Zeichen!
string.isdecimal() Überprüft auf Zahlen – wenn alle Zeichen Dezimalzahlen sind, wird True zurückgeliefert
string.isdigit() Überprüft auf Numerische und digitale Zeichen z.B. ‚123‘ oder '3\u00B2' (was 3 hoch 2
entspricht!)
inhalt = "Beispieltext"
ergebnis = inhalt.isalnum()
print(ergebnis)
Ergebnis:
True
Sobald Leerzeichen vorkommen, sind nicht mehr alle Zeichen alphanumerisch und somit
kommt beim folgenden Beispiel False zurück:
False
inhalt = "Beispieltext"
ergebnis = inhalt.isalpha()
print(ergebnis)
Ergebnis:
True
inhalt = "123Beispieltext"
ergebnis = inhalt.isalpha()
print(ergebnis)
False
© https://www.python-lernen.de/methode-string-split.htm Seite 63
Als Ergebnis erhalten wir eine Liste. Listen lernen wir im Kapitel https://www.python-
lernen.de/listen.htm kennen.
Achtet man nun genau auf den zurückgelieferten Inhalt, sieht man vor ' nachname' und ' alter'
jeweils ein Leerzeichen. Diese Leerzeichen sind oft unerwünscht, können aber sehr einfach mit
der Methode strip() entfernt werden. Oder man achtet bereits beim Ausgangsmaterial
darauf, dass keine Leerzeichen nach den Kommas vorhanden sind.
Wenn man allerdings sicher weiß, dass immer im Ausgangsmaterial nach dem Komma ein
Leerzeichen kommt, kann man dies auch als Parameter nutzen! Der Parameter kann also aus
einer beliebigen Zeichenkombination bestehen. Wir übergeben der Methode bei unserem
Beispiel neben dem Komma auch das Leerzeichen:
Wird also split() ohne Parameter aufgerufen, erfolgt eine Trennung bei jedem Leerzeichen!
Jetzt werden die Kommas als Inhalt angesehen und sind bei der Liste in „vorname,“ und
„nachname,“ gelandet.
Interessant ist noch, dass mehrere Leerzeichen (falls vorhanden) als eines angesehen werden.
Wir erhalten das gleiche Ergebnis wie oben bei folgenden String:
daten = "vorname,nachname,alter"
einzeldaten = daten.split(",", 1)
print(einzeldaten)
['vorname', 'nachname,alter']
Wir bekommen also als Anzahl von Listenelemente unsere Anzahl von Trennungen + 1.
Die englische Zusammenziehung liest sich ungewohnt. Übersetzt man es ein wenig „holprig“
ins deutsche, ist die Funktion der Methode klar: ends = wird beendet, endet / with = mit
inhalt = "https://www.python-lernen.de"
ergebnis = inhalt.endswith(".de")
print(ergebnis)
True
Wir können also überprüfen, ob es zutrifft (hier in unserem Fall, ob es eine deutsche
Domainendung ist).
Damit können wir auch in eine if -Abfrage gehen oder in eine while -Schleife.
inhalt = "https://www.python-lernen.de"
ergebnis = inhalt.endswith(".de", 0, 28)
print(ergebnis)
Sobald wir 27 eingeben haben wir zur Überprüfung nur noch „…python-lernen.d“ – und somit
kein „.de“ mehr.
Wertesammlung.
Nehmen wir an, wir wollen unseren String überprüfen, ob die URL mit einer dieser Endungen
endet:
.de
.com
.net
Also nehmen wir alle 3 Fälle (unsere Wertesammlung) auf und es soll, wenn einer der Fälle
zutrifft „True“ zurückgeliefert werden. Wir erstellen aus unseren Fällen ein Tupel (siehe
entsprechendes Kapitel https://www.python-lernen.de/tupel.htm)
inhalt = "https://www.python-lernen.de"
datentyp_tupel = (".de", ".com", ".net")
ergebnis = inhalt.endswith(datentyp_tupel)
print(ergebnis)
Jetzt kann die URL auf „.de“ oder auf „.com“ oder auf „.net“ enden und wir erhalten ein „True“
zurück.
Öfters wird man diese Konstruktion sehen. Hier ist schneller ersichtlich, dass ein Tupel
eingesetzt wird:
inhalt = "https://www.python-lernen.de"
ergebnis = inhalt.endswith((".de", ".com", ".net"))
print(ergebnis)
© https://www.python-lernen.de/methode-string-startswith.htm Seite 67
Die englische Zusammenziehung liest sich ungewohnt. Übersetzt man es ein wenig „holprig“
ins deutsche, ist die Funktion der Methode klar:
with = mit
Wir können also Überprüfen, ob bei einem String der Anfang einer von uns bestimmten
Zeichenfolge entspricht.
Nehmen wir an, wir haben als String als Text eine URL und wollen überprüfen, ob diese mit
„https://“ startet.
inhalt = "https://www.python-lernen.de"
ergebnis = inhalt.startswith("https://")
print(ergebnis)
Als Rückmeldung erhalten wir „True“, da die Überprüfung korrekt war. Würde die URL
allerdings mit „http://“ starten, kommt ein „False“ zurück:
inhalt = "http://www.python-lernen.de"
ergebnis = inhalt.startswith("https://")
print(ergebnis)
Wir können also auch festlegen, ab welcher Position angefangen wird, die Überprüfung zu
starten und bis zu welcher Position.
https://
http://
Und diese beide Fälle können wir als Tupel (siehe entsprechendes Kapitel) schreiben:
Und genau dieses Tupel können wir als Kontrollwert unserer Methode .startswith()
übergeben und erhalten ein „True“ als Rückgabewert, wenn einer der Werte des Tupels
zutrifft.
inhalt = "https://www.python-lernen.net"
urlanfang_als_tupel = ("https://", "http://")
ergebnis = inhalt.startswith(urlanfang_als_tupel)
print(ergebnis)
Öfters ist auch die Methode in der folgenden Schreibweise anzutreffen (auf die 2 runden
Klammern achten!):
inhalt = "https://www.python-lernen.net"
ergebnis = inhalt.startswith(("https://", "http://"))
print(ergebnis)
© https://www.python-lernen.de/string-methode-expandtabs.htm Seite 69
string.expandtabs([Anzahl_Leerzeichen])
Beispiele:
© https://www.python-lernen.de/string-methode-expandtabs.htm Seite 70
print("01234567890123456789012345678901234567890123456789")
print(inhalt.expandtabs(2), " (Tabstopp bei 2)\n")
print("01234567890123456789012345678901234567890123456789")
print(inhalt.expandtabs(3), " (Tabstopp bei 3)\n")
print("01234567890123456789012345678901234567890123456789")
print(inhalt.expandtabs(4), " (Tabstopp bei 4)\n")
print("01234567890123456789012345678901234567890123456789")
print(inhalt.expandtabs(5), " (Tabstopp bei 5)\n")
print("01234567890123456789012345678901234567890123456789")
print(inhalt.expandtabs(6), " (Tabstopp bei 6)\n")
print("01234567890123456789012345678901234567890123456789")
print(inhalt.expandtabs(7), " (Tabstopp bei 7)\n")
print("01234567890123456789012345678901234567890123456789")
print(inhalt.expandtabs(8), " (Tabstopp bei 8)\n")
print("01234567890123456789012345678901234567890123456789")
print(inhalt.expandtabs(9), " (Tabstopp bei 9)\n")
print("01234567890123456789012345678901234567890123456789")
print(inhalt.expandtabs(10), " (Tabstopp bei 10)\n")
01234567890123456789012345678901234567890123456789
Textinhalt 1234567890 mehr Inhalt (Standardeinstellung 8)
01234567890123456789012345678901234567890123456789
Textinhalt 1234567890 mehr Inhalt (Tabstopp bei 2)
01234567890123456789012345678901234567890123456789
Textinhalt 1234567890 mehr Inhalt (Tabstopp bei 3)
01234567890123456789012345678901234567890123456789
Textinhalt 1234567890 mehr Inhalt (Tabstopp bei 4)
01234567890123456789012345678901234567890123456789
Textinhalt 1234567890 mehr Inhalt (Tabstopp bei 5)
01234567890123456789012345678901234567890123456789
Textinhalt 1234567890 mehr Inhalt (Tabstopp bei 6)
01234567890123456789012345678901234567890123456789
Textinhalt 1234567890 mehr Inhalt (Tabstopp bei 7)
01234567890123456789012345678901234567890123456789
Textinhalt 1234567890 mehr Inhalt (Tabstopp bei 8)
01234567890123456789012345678901234567890123456789
Textinhalt 1234567890 mehr Inhalt (Tabstopp bei 9)
01234567890123456789012345678901234567890123456789
Textinhalt 1234567890 mehr Inhalt (Tabstopp bei 10)
Auch wenn es so wirkt, als würde sich bei der Einstellung für dem Tabstopp für 2, 3 wie auch
bei 4 nichts ändern, passt das Verhalten durchaus. Im Beispiel liegt bei allen 3 Einstellungen
der Beginn nach dem ersten umgewandelten Tab bei 12. Und 12 ist ein Vielfaches von 2,3 und
4.
Bis zur Position 10 ist alles belegt durch den vorherigen Text plus eines Leerzeichens. Also
kann erst nach 10 der Tab „wirken“. Schauen wir uns die Reihen an:
Die 5er-Reihe ist anders, da hier unser Text bei 15 startet 5,10 (alles nicht möglich), 15 (startet
unser Text)
© https://www.python-lernen.de/string-methode-partition.htm Seite 72
string.partition("Suchtext")
den Suchtext
Schauen wir es am Beispiel an. Wir haben den Satz „Python ist einfach zu lernen“. Jetzt wollen
wir diesen Text zerlegen, und zwar bei dem Wort „ist“.
Das Ergebnis ist als Datenform ein Tupel und wir erhalten:
Bitte ein Augenmerk darauf, dass nichts verloren geht! Es werden auch alle Leerzeichen um der
Suchwert „ist“ behalten. Dieser finden sich nach dem ersten Wert des Tupels nach „Python “
und vor dem dritten Wert „ einfach zu lernen“.
Im Ergebnis sieht man schön, dass nur das erste Auftreten des Suchtextes berücksichtigt wird.
Das zweite „ist“ in unserem Beispiel endet im dritten Rückgabewert des Tupels.
Hier wird das Ergebnis für das Verständnis der Funktion von .partition() wichtig. Als
Rückgabe-Tupel erhalten wir:
© https://www.python-lernen.de/string-methode-partition.htm Seite 73
Unser Suchtext ist in dem Tupel also immer der zweite Wert! Tritt er im Text in der ersten
Position auf, kommt vor ihm also nichts. Somit bleibt der erste Wert unseres Rückgabetupels
leer und im dritten Wert steht alles nach dem „ist“.
Ergebnis:
Man sieht an diesem Beispiel auch, dass Groß- und Kleinschreibung einen Unterschied macht.
Gibt man anstelle des Suchtextes keinen Parameter ein ergebnis = satz.partition() ,
erhält man die Fehlermeldung: „TypeError: partition() takes exactly one argument (0 given)“
Für das Aufspalten muss also ein sinnvoller Wert mitgegeben werden. Wobei ein Leerzeichen
auch ein sinnvoller Wert ist:
Befehlsaufbau:
str = trennzeichen.join(Aufzählung)
Axel#Elke#Martin
Wir erhalten aus dem Datentyp Liste eine String. Die einzelnen Elemente sind durch „#“
getrennt.
Die Nutzung von join() ist anhand von dem Datentyp Listen einfacher verständlich und die
Mächtigkeit der Methode schnell klar. Es funktioniert genauso mit Zeichenketten („Strings“).
Allerdings wird jedes Zeichen des Textes getrennt durch das Trennzeichen vom nächsten
Zeichen:
zeichenkette = "abcd"
trennzeichen = '#'
ergebnis = trennzeichen.join(zeichenkette)
print(ergebnis)
a#b#c#d
Wir können die Datentyp „List“, „Tupel“, „String“, „Dictionary“ und „Set“ nutzen und join()
übergeben.
null#eins
Anstelle eines Ergebnisses erhalten wir die Fehlermeldung: „TypeError: sequence item 0:
expected str instance, int found“
© https://www.python-lernen.de/operatoren-strings.htm Seite 76
print( 3 * 'mi' );
mimimi
Ein Operator ist eine mathematische Vorschrift. So steht das „*“ wie üblich in der Mathematik
für die Multiplikation – wenden wir diese Multiplikation in Python auf einen Text an, wird dieser
entsprechend oft wiederholt.
Anmerkung am Rande – wem "mimimi" nichts sagt, unbedingt die Videos der Muppets
ansehen unter https://www.youtube.com/watch?v=VnT7pT6zCcA.
mimimimo
Allerdings funktioniert das bei 2 Variablen nicht und es gibt eine Fehlermeldung. Versucht man
bei Variablen folgende Programm:
variable1 = "ich"
variable2 = "du"
print( variable1 variable2 )
Es klappt dann wieder, wenn wir ein Pluszeichen mitgeben. Daher bietet es sich an, das
Pluszeichen immer zu machen (auch bei Zeichenketten, wo es eigentlich ohne gehen würde).
variable1 = "ich"
variable2 = "du"
print( variable1 + variable2 )
Im Folgendem ein kleines Beispiel: Nicht besonders schön programmiert, aber es funktioniert.
Schöner geht es dann, wenn wir im Kurs Schleifen kennengelernt haben.
print( 3 * '*' );
print( 5 * '*' );
print( 8 * '*' );
print( 9 * '*' );
print( 10 * '*' );
print( 9 * '*' );
print( 8 * '*' );
print( 5 * '*' );
print( 3 * '*' );
© https://www.python-lernen.de/grundrechenarten-in-python.htm Seite 78
3 + 3
print(3 + 3)
Der Übersichtlichkeit halber wird in diesem Kapitel immer die kurze Form verwendet.
Das klappt natürlich auch mit Minus (dann allerdings kommt ein anderes Ergebnis raus).
3 - 3
Multiplizieren
Irgendwann kam in der Schule noch multiplizieren und teilen im Mathematikunterricht. Auch
das können wir mit den gewohnten mathematischen Zeichen bewirken:
3 * 3
Division
Und wir bereits in der Schule ist ein Teilen durch das "/" möglich aber auch in Python ist ein
Teilen durch 0 nicht möglich.
3/3
Ergibt als Ergebnis "1". Versuchen wir durch "0" zu teilen, bekommen wir eine Fehlermeldung!
3/0
Dies führt zu einer Fehlermeldung "Traceback …" mit einer Angabe der Programmzeile („line
X“), wo der Fehler aufgetreten ist. Zusätzlich bekommen wir die Fehlerbezeichnung in Englisch.
In diesem Fall dann "ZeroDivisionError: … division by zero".
Modulo in Python
Sehr viel später in der Schule ist ein Teilen mit "Rest" angesagt. Mathematiker würden diese
mathematische Funktion als Modulo (mod) bezeichnen, die als Ausgabe den Rest bei einer
Division ganzer Zahlen als Rückgabe liefert.
Im folgenden Beispiel wird es nachvollziehbar und verständlich. Die Schreibweise von Modulo
ist das Prozentzeichen. Wir wollen nun den Rest der Division von 7 und 2 erhalten:
7%2
© https://www.python-lernen.de/grundrechenarten-in-python.htm Seite 79
Als Ergebnis bekommen wir „1“. Die 2 geht 3-mal komplett in die 7 - sprich 2+2+2 ergibt 6 und
dann bleibt von der 7 eine 1 übrig.
Wir können auch anstelle des Rests die Anzahl erhalten, wie oft die Zahl in zu teilende Zahl
„komplett rein geht“. Bei unserem obigen Beispiel mit
7//2
erhalten wir dann 3. Unsere 2 geht 3-mal in die 7 und der Rest wird ignoriert. Jetzt haben wir
auch schon die Schreibweise eingeführt. Hier haben wir einfach 2 x "/".
Hoch irgendwas
Was fehlt noch an den typischen Funktionen? Das typische "hoch" – sprich in der netten
mathematischen Schreibweise 23. Hier haben wir dann als Schreibweise in Python:
2**3
Gerechnet wird intern "2 * 2 * 2" und als Ergebnis erhalten wir "8". Bei 3 2 erhalten wir 9.
Quadratwurzel
Wer jetzt noch das Wurzelziehen vermisst. Die Quadratwurzel ist der einfachste Fall. Der läuft
über den Kniff mit 0.5
9**0.5
Als Ergebnis bekommen wir die „3“. Hier sehen wir auch, dass die Schreibweise in Python
immer mit Punkt geschrieben werden – im Deutschen spricht man von Nachkommazahlen!
Wir haben also in Python „NachPUNKTzahlen“.
Möchte man nicht nur die Quadratwurzel ziehen, dann wird das Modul „math“ benötigt, dass
erst später im Kurs eingeführt wird. Der Vollständigkeit halber einfach hier die Schreibweise:
import math as m
print(m.sqrt(25))
# schlecht lesbar
zahl1 = 1000000
zahl2 = 100000000
print(zahl1 + zahl2)
# gut lesbar
zahl3 = 1_000_000
zahl4 = 100_000_000
print(zahl3 + zahl4)
Es ist und bleibt auch eine Integer-Zahl. Mit der Anweisung type() können wir den Variablen-
Typ anfragen.
zahl3 = 1_000_000
print(type(zahl3))
<class 'int'>
© https://www.python-lernen.de/listen.htm Seite 81
Wenn man sich vorstellt, dass man ein Telefonbuch in Variablen speichern möchte, dann hätte
man wilde Konstruktionen wie:
vorname1 = 'Axel'
vorname2 = 'Elke'
vorname3 = 'Martin'
Aber wo soll das enden? Das wäre als eine wenig handliche Vorgehensweise. Und daher gibt
es sogenannte „Listen“ in Python. Wer schon eine andere Programmiersprache kennt, hier wird
diese Möglichkeit Array genannt.
Wie können wir in Python nun in Listen Inhalte speichern? Ganz einfach über die eckigen
Klammern
Es werden nun alle Vornamen ausgegeben. Wollen wir nun nur einen bestimmten Vornamen
ausgeben, müssen wir die Index-Nummer mitgeben. Diese wird in einer eckigen Klammer
geschrieben.
Elke
Warum nicht das erste Element unserer Liste, was ja offensichtlich den Inhalt „Axel“ enthält?
Hier ist es wichtig, dass Computer immer bei 0 anfangen zu zählen, insbesondere bei Listen.
Wollen wir also das erste Element unserer vornamen-Liste erhalten, müssen wir als Index 0
angeben:
Jetzt bekommen wir das erste Element der Liste. Daher der wichtige Merksatz
Listenwerte überschreiben
Wollen wir einen bestehenden Listeneintrag überschreiben, weil aus dem Martin eine Martina
geworden ist, können wir das über die Index-Nummer und einer neuen Wertzuweisung machen:
Nun wird die bestehende Liste um diese 2 Elemente erweitert. Lassen wir die Liste ausgeben,
erhalten wir:
Python stellt verschiedene Funktion für Listen zur Verfügung. Hier gibt es eine Funktion zum
Erweitern von Listen: listenname.append('neuer Wert') . Als konkretes Beispiel sieht
das nun so aus:
Unser Beispiel von oben wandeln wir ab. Wir wollen nicht mehr die bestehende Liste mit den
Vornamen erweitern, sondern durch einen komplett anderen Inhalt ersetzen:
del(vornamen)
vornamen = ['Heike', 'Sabine']
print(vornamen)
Wichtig war, dass der Index einer Liste immer bei 0 beginnt!
Und hier kommt auch die Schreibweise zum Vorschein. Als Erstes wird das Objekt genannt und
dann wird die Methode an dieses Objekt mit einem Punkt „verkettet“. Gegebenenfalls kann
man noch weitere Parameter für die Funktionsweise der Methode mit übergeben. Klarer wird
es im konkreten Beispiel (natürlich hier mit Listen).
Nutzen wir die Liste mit den Vornamen und lassen uns den zweiten Namen (sprich
Indexnummer 1) ausgeben:
Jetzt wenden wir die Methode upper() auf unser Objekt (in diesem Fall einen String) an.
Unsere Ausgabe vom Listenobjekt mit dem Index 1 wird mit der Methode „schreib alles groß“
bzw. upper() verbunden:
© https://www.python-lernen.de/listen-methoden.htm Seite 85
ELKE
Der Inhalt der Liste selber ändert sich nicht, sondern nur die Ausgabe wird in Großschreibung
gebracht.
Hier haben wir das erste Beispiel für eine Methode, die keine weiteren Angaben braucht. Es soll
ja einfach alles in Großbuchstaben geschrieben werden.
Schauen wir im nächsten Beispiel Methoden an, die weitere Angaben benötigen, damit sie ihre
Funktion auch erfüllen können.
buchstaben = []
print(buchstaben)
Wir haben also mit der Liste „buchstaben“ ein Objekt. Diesem Listenobjekt wollen wir einen
weiteren (in diesem Fall den ersten) Eintrag anhängen. Also wenden wir append() an:
buchstaben = []
print(buchstaben)
buchstaben.append('a')
buchstaben.append('b')
print(buchstaben)
[]
['a', 'b']
In der ersten Zeile sehen wir, dass eine leere Liste existiert.
Dann wird über append() zweimal ein Buchstabe angefügt. Dieser wird jeweils am Ende der
Liste eingetragen!
Weil es so schön übersichtlich ist, nutzen wir wieder unser Buchstabenbeispiel und wollen nun
in der bestehenden Liste mit ['a', 'b'] ein „c“ zwischen „a“ und „b“ schieben (sprich einfügen).
Beide Angaben werden in den Runden Klammern der Methode mit übergeben. Vergisst man
Angaben, erhält man den Fehler „TypeError: insert() takes exactly 2 arguments (1 given)“. Die
Reihenfolge ist:
['a', 'b']
['a', 'c', 'b']
['a', 'b']
['b']
Hier wurde mal eine Anweisung (und keine Methode eingeschmuggelt)! Aber es gibt auch
Methoden, um Elemente aus Listen zu löschen.
['a', 'b']
['a']
Versuchen wir einen Wert zu löschen, der nicht in der Liste existiert, erhalten wir die
Fehlermeldung „buchstaben.remove('e')
ValueError: list.remove(x): x not in list”
Diese Fehlermeldungen können wir später über bestimmte Techniken abfangen, jetzt müssen
wir vorerst damit noch leben.
buchstaben_sortiert = sorted(buchstaben)
print(buchstaben_sortiert)
Das Ergebnis:
Soll bei der Sortierreihenfolge nicht auf Groß- und Kleinschreibung geachtet werden, muss die
entsprechende Anweisung mitgegeben werden.
Damit lassen sich viele Aufgaben bei Listen schnell und einfach erledigen!
© https://www.python-lernen.de/listen-methoden.htm Seite 89
© https://www.python-lernen.de/list-methoden-uebersicht.htm Seite 90
>>> dir(list)
Methode Beschreibung
.index() suchen nach Element in Liste und liefert Index (Nummern fangen bei 0 an!) zurück
.insert() fügt einen Eintrag an der vorgegebenen Index-Nummer ein (folgende Einträge werden nach hinten
verschoben)
.pop() löscht den Eintrag aus der Liste des übergebenen Index und liefert dessen Inhalt als Rückgabewert
.remove() löscht den Eintrag aus der Liste (im Gegensatz zu pop() wird der Wert und nicht der Index übergeben)
Was kommt als Ausgabe? Wir erhalten als Ausgabe nur ein
Was passiert nun. Auch beim String beginnt die Zählung bei 0 - unser erstes Zeichen "I" ist als
am Index 0 zu finden. Wir haben die Index-Nummer 1 angefragt und bekommen das zweite
Zeichen vom String. Daher erhalten wir als Ausgabe das "c".
Wir können also die Vorgehensweise von Listen auch auf Variablen anwenden.
Ausgabe rückwärts
Wie bei Listen schon gesehen, können wir auch die Ausgabe von hinten uns anzeigen lassen.
Wenn wir den letzten Buchstaben (sprich -1) uns ausgeben lassen möchten, ist unsere
Anweisung:
Unser vorheriges Beispiel erweitern wir. Es sollen nicht nur 1, sondern 6 Zeichen ausgelesen
werden:
Als Ausgabe erhalten wir direkt ab dem Anfang (daher die 0) die folgenden 5 Zeichen:
Ich b
Hier gibt es auch die Kurzschreibweise. Man kann vor oder nach dem Doppelpunkt auch
keine Angabe machen. Dann wird von Anfang an (wenn vor dem Doppelpunkt nichts
angegeben wird) oder bis zum Schluss (wenn nach dem Doppelpunkt nichts angegeben wird)
ausgegeben.
eine Variable
Ich bin
Natürlich können wir auch die Variante mit der "Zählung ab dem Ende" einsetzen:
able
21
© https://www.python-lernen.de/python-dictionary.htm Seite 93
Schauen wir uns den Aufbau anhand einer deutsch-englisch Wörterbuches an.
null = zero
eins = one
zwei = two
drei = three
Als Dictionary wird in Python im ersten Schritt ein leeres „Wörterbuch“ erstellt – dies ist an den
geschweiften Klammern zu sehen. Wir nennen es „deutschenglisch“:
deutschenglisch = {}
deutschenglisch = {}
deutschenglisch['null'] = 'zero'
deutschenglisch['eins'] = 'one'
deutschenglisch['zwei'] = 'two'
deutschenglisch['drei'] = 'three'
deutschenglisch
>>> deutschenglisch
Diese folgende Variante ist auch eine andere Möglichkeit, ein „Dictionary“ aufzubauen:
Wollen wir ein bestimmtes Element der assoziativen Liste erhalten, geben wir das gewünschte
einfach mit dem „Klartext-Index“ an.
>>> deutschenglisch['zwei']
'two'
del deutschenglisch['zwei']
>>> deutschenglisch
Wird kein Index (Schlüssel-Wert Paar) angegeben, wird das komplette dictionary gelöscht!
del deutschenglisch
>>> deutschenglisch
values()
Über die Methode values() werden alle Werte des dictionary zurückgeliefert. Aus unserem
vorherigen Wörterbuchbeispiel wäre das dann:
deutschitalienisch.values()
Ergebnis:
>>> deutschitalienisch.values()
keys()
Über die Methode keys() werden alle Schlüssel des dictionary zurückgeliefert. Aus unserem
vorherigen Wörterbuchbeispiel wäre das dann:
deutschitalienisch.keys()
© https://www.python-lernen.de/python-dictionary.htm Seite 95
>>> deutschitalienisch.keys()
items()
Über die Methode items() werden alle Elemente des dictionary zurückgeliefert. Aus
unserem vorherigen Wörterbuchbeispiel wäre das dann:
deutschitalienisch.items()
Ergebnis:
>>> deutschitalienisch.items()
clear()
Alle Elemente werden aus dem dictionary gelöscht. Im Unterschied zum vorher gezeigten del
besteht weiterhin ein dictionary mit seinem Namen, dass allerdings keinen Inhalt hat.
deutschitalienisch.clear()
copy()
Legt eine Kopie des dictonary an.
woerterbuch = deutschitalienisch.copy()
Nun steckt der Inhalt auch in dem neuen „dictionary“, dass aber diesen Inhalt so behält, auch
wenn das Original verändert wird. Hier liegt der Unterschied zu einem Aliasnamen (siehe weiter
unten).
>>> woerterbuch
Wird mit Aliasnamen gearbeitet (und nicht mit Kopien) verändert sich der Inhalt, egal ob man
mit dem Alias oder dem originalen Namen zugreift!
© https://www.python-lernen.de/python-dictionary.htm Seite 96
neuernamen = deutschitalienisch
deutschitalienisch['vier'] = 'quattro'
neuernamen['vier']
Wir erhalten als Ausgabe dann „quattro“. Die Änderungen gelten für alle Aktion, egal ob
Elemente dazukommen oder entfernt werden.
© https://www.python-lernen.de/dictionary-methoden-uebersicht.htm Seite 97
>>> dir(dict)
Methode Beschreibung
.items() Gibt alles Schlüssel und Werte aus (bei Python 2.7 .viewitems())
.pop() löscht den Eintrag aus dem Dictionary des übergebenen Schlüssels und liefert dessen Inhalt als
Rückgabewert
.popitem() Liefert einen Eintrag als Tupel zurück und löscht den Eintrag aus dem Dictionary (im Gegensatz zu
pop() muss kein Schlüssel übergeben werden)
.setdefault() liefert den Wert eines Eintrags aus dem Dictionary, wenn der Schlüssel vorhanden ist. Ist kein
entsprechender Schlüssel vorhanden, wird ein Schlüssel mit dem Wert im Dictionary gespeichert
.update() Aktualisiert einen Wert, wenn der Schlüssel vorhanden ist. Wenn noch kein entsprechender Schlüssel
vorhanden ist, wird Wert und Schlüssel eingetragen
Und was ist ein Tupel? Eigentlich eine Liste aber der wichtige Unterschied ist, dass der Inhalt
eines Tupels NICHT änderbar ist. Daher sind Tupel besonders geeignet, um Konstanten zu
verkörpern.
Technisch möglich ist es auch ohne Klammern – aber erstens unüblich und zweitens für den
typischen Python-Programmierer irritierend.
Und hat man ein Tupel mit nur einem einzigen Element ist das Komma am Schluss wichtig!
Einfach mal folgenden Code testen:
inhaltA = ('wert1',)
inhaltB = ('wert2')
type(inhaltA)
type(inhaltB)
Warum wir überhaupt Tupel nutzen sollen ist anhand der obigen Beispiele wenig einsichtig. Wie
gesagt, Tupel sind die Speicherform von unveränderbaren Daten – was man in anderen
Programmiersprachen als Konstanten bezeichnet. Solche Daten wäre z.B. Name
Über die eckigen Klammern greife ich per Index auf den entsprechenden Wert zu. Auch wie bei
Listen startet der Index bei 0!
Ich kann auch mehrere Werte anhand von „von – bis“ auswählen:
('wert3', 'wert4')
© https://www.python-lernen.de/tuple-methoden-uebersicht.htm Seite 100
>>> dir(tuple)
Methode Beschreibung
vornamen = ( "Hans","Peter","Elke","Peter","Sabine","Elke")
print(vornamen)
vornamen = ( "Hans","Peter","Elke","Peter","Sabine","Elke")
print(vornamen)
print (vornamen.index("Peter"))
Ganz wichtig – die Zählung beginnt bei 0. Daher kommt die 1 beim Suchen nach „Peter“, der an
der zweiten Stelle steht.
© https://www.python-lernen.de/tuple-methoden-uebersicht.htm Seite 101
Sollte das Gesuchte nicht in dem Tuple vorhanden sein, erhalten wir als Rückmeldung
„ValueError: tuple.index(x): x not in tuple“
© https://www.python-lernen.de/mengenlehre-set-frozenset.htm Seite 102
In einem Set steckt eine ungeordnete Sammlung von Objekten, die nur 1-Mal vorkommen!
In einem Set steckt eine ungeordnete Sammlung von Objekten, die nur 1-Mal vorkommen! Dies
sieht man sehr schön, wenn man ein Tupel mit Dopplungen in ein set umwandelt:
werte_als_tupel = (1,1,1,3,5,3,4,5,3)
werte_als_set = set(werte_als_tupel)
print(werte_als_set)
Als Ergebnis erhalten wir dann ein Set mit jeweils nur einmalig vorkommenden Werten:
{1, 3, 4, 5}
Wollen wir nun die Schnittmenge (also was in beiden Mengen vorkommt) herausfiltern, läuft
dies über das kaufmännische Und & :
{2, 3, 'B'}
print("Set A:")
print(set_a)
print("Set B:")
print(set_b)
print()
Set A:
{1, 2, 3, 'A', 'B', 'C'}
Set B:
{2, 3, 'D', 'B'}
Vereinigungsmenge über |
{1, 2, 3, 'A', 'B', 'C', 'D'}
Differenzmenge über -
{'C', 1, 'A'}
Die Umwandlung kann man vorwärts wie rückwärts machen, sprich aus einem Set ein
Frozenset und rückwärts.
print(set_c)
print(type(set_c))
Ergebnis:
print(set_c)
print(type(set_c))
set_c = set(set_c)
print(set_c)
print(type(set_c))
inhalt = "anzahl"
# sortieren
buchstabensortiert = sorted(buchstabenliste)
print(buchstabensortiert)
a : Anzahl 2
h : Anzahl 1
l : Anzahl 1
n : Anzahl 1
z : Anzahl 1
: Anzahl 1
B : Anzahl 1
a : Anzahl 1
b : Anzahl 1
c : Anzahl 1
e : Anzahl 2
h : Anzahl 2
l : Anzahl 1
n : Anzahl 2
s : Anzahl 1
t : Anzahl 1
u : Anzahl 1
z : Anzahl 1
ä : Anzahl 1
© https://www.python-lernen.de/set-methoden-uebersicht.htm Seite 107
>>> dir(set)
Methode Kurzbeschreibung
.difference() liefert ein neues Set mit der Rückgabe der Unterschiede der übergebenen Sets
.intersection() liefert ein neues Set zurück mit den Werten der Überschneidung der übergebenen
Sets
.intersection_update() aktualisiert ein Set mit den Überschneidungen zwischen sich selber und dem
übergebenen Set
.isdisjoint() Überprüft, ob 2 Sets keinerlei Überschneidungen haben. Als Rückgabe wird „True“
oder „False“ geliefert
.issubset() Überprüft, ob das Set im anderen Set enthalten ist. Rückgabe „True“ oder „False“
.issuperset() Überprüft, ob jedes Element des Sets im anderen Set enthalten ist. Rückgabe
„True“ oder „False“
.pop() Liefert vom Set ein zufälliges Element zurück und löscht dieses aus dem Set
.remove(wegmitdiesem) Löscht ein Element (das übergeben wird) aus einem Set
.symmetric_difference() liefert ein neues Set zurück mit allen Werten beider Sets, die sich nicht
überschneiden der übergebenen Sets
.symmetric_difference_update() aktualisiert ein Set mit den Werten beider Sets, bei denen keine Überschneidungen
zwischen sich selber und dem übergebenen Set vorliegt
.update() aktualisiert ein Set mit allen Werten von sich selber und den übergebenen Sets
© https://www.python-lernen.de/input-nutzereingaben.htm Seite 108
Um eine Angabe vom Nutzer anzufordern, gibt es in Python den Befehl input
Diesem Befehl können wir einen Text mitgeben, damit dem Nutzer klar ist, was er denn
eingeben soll. Die Eingabe selber wird in einer Variablen gespeichert, mit der wir dann
weiterarbeiten können.
Das Python-Programm pausiert nun, wenn es diese Programmzeile erreicht hat und wartet ab,
bis der Nutzer eine Eingabe gemacht hat. Erst nach der Eingabe läuft das Programm dann
weiter.
Nun können wir die Variable, die im Beispiel „benutzereingabe“ genannt wurde, im weiteren
Programmablauf nutzen.
class 'str'
Wollen wir aber mit der vom Benutzer eingegebenen Zahl weiterrechnen, müssen wir den
String erst in eine Zahl konvertieren.
Hier kommt das Prinzip des „castens“ zum Einsatz. Der Typ einer Variablen umgewandelt.
Wenn man den Typ einer Variablen umwandelt, spricht man „casting“. Das Wort erinnert nicht
zu Unrecht an das Besetzen von Filmrollen (also die Rollenverteilung). Und genau das machen
wir mit dem Typ. Wir sagen, du bist nun eine Ganzzahl (integer).
benutzereingabe = int(benutzereingabe)
Jetzt können wir mit der Benutzereingabe als Zahl arbeiten. Diese Zahl können wir über
print ausgeben lassen.
print(benutzereingabe)
© https://www.python-lernen.de/input-nutzereingaben.htm Seite 109
Wollen wir nun die Zahl mit einem Text am Anfang ausgeben lassen, kommen kleine Probleme
zum Vorschein:
Wir versuchen nun die STRING-Ausgabe "Eingegeben wurde" mit einer Integer zu verknüpfen
und das wird mit einer Fehlermeldung quittiert. Hier müssen wir den Typ wieder umwandeln
und alles ist gut:
Gibt der Benutzer allerdings die Zahl in andere Form ein (sprich keine Zahl), dann bekommt
man Fehlermeldungen.
zum Testen von Code, bzw. zum Verhindern der Ausführung auskommentierter
Programmteile
erklärende Kommentare
Wird ein Programm komplexer und man betreut es über Jahre bzw. mehrere Personen
arbeiten an einer Software, ist es hilfreich, Codeabschnitte zu kommentieren. Dadurch ist
auch noch Jahre später schnell klar, warum etwas an einer bestimmten Stelle in der
entsprechenden Art umgesetzt wurde.
Als Einsteiger wird man aber eher von der folgenden Art profitieren:
Beispiel:
Die Kommentare können auch nach Befehlen platziert werden. Ab dem Doppelkreuz „#“ wird
alles ignoriert!
Soll ein Code auskommentiert („ausgeschaltet“) werden, wird das Doppelkreuz einfach am
Anfang der Zeile platziert:
© https://www.python-lernen.de/kommentare.htm Seite 111
# print("Hallo")
print("Welt")
Als Ergebnis erhalten wir nur noch als Ausgabe das Wort „Welt“. Die Zeile mit der Ausgabe für
„Hallo“ wird durch das Kommentarzeichen komplett ignoriert.
"""
Hier kommt auskommentierter Bereich
der über mehrere Zeilen sich zieht
"""
Am Ende kommen dann wieder 3 doppelte Anführungszeichen. Ab jetzt werden wieder alle
Python-Befehle ausgeführt.
Dieses Vorgehen kann man sowohl zum Platzieren von umfangreichen Kommentaren nutzen
wie auch um ganze Programmteile auszukommentieren:
"""
print("Hallo")
print("Welt")
"""
© https://www.python-lernen.de/ausfuehrbares-python-programm-erstellen.htm Seite 112
Es ist egal, mit welchem Betriebssystem wir arbeiten. Im Beispiel wird unter Windows der im
Betriebssystem vorhandene Editor „notepad“ verwendet.
Die einfachste Variante ist, auf Start zu klicken und dann einfach loszutippen. Sobald wir die
ersten Buchstaben von „editor“ eingetippt haben bekommen wir bereits den Vorschlag für den
Standardeditor.
print('Hallo Welt')
Beim Speichern auf die Dateiendung „.py“ achten! Als Dateiname verwende ich für unser erstes
Programm „hallowelt.py“.
Ist bei Installation von Python nun der Pfad im Betriebssystem richtig hinterlegt worden,
können in direkt in der DOS-Konsole Python starten. Zum Test kann man Python ohne unser
geschriebenes Programm starten. Einfach direkt in der DOS-Konsole „python“ eintippen.
Klappt das, können wir unser Python-Programm „hallowelt.py“ starten. Dazu werden nach dem
Programmaufruf noch der Pfad und der Dateiname angegeben.
python c:\python-kurs.de\hallowelt.py
Wir erhalten durch die Ausführung des Programms nun die Ausgabe in der Konsole von „Hallo
Welt“.
Wenn wir uns den langen Pfadnamen zum eintippen sparen wollen, können wir einmal in das
Verzeichnis wechseln über die DOS-Anweisungen cd und dann das Programm ohne
Pfadangaben ausführen. Einfach sich den folgenden Screenshot ansehen. Hier wird am Anfang
das Programm mit Pfadangabe ausgeführt und dann wird in den Ordner „Python-Kurs.de“
gewechselt (sieht aus wie eine Internetadresse, kann man aber auch als Verzeichnis
verwenden (ein bisschen Werbung und Kopierschutz)).
Zum Starten von unserem Programm geben wir im Terminal nach dem Startbefehl für Python
noch den Pfad und den Dateinamen an:
python3 Documents/Python-Kurs.de/hallowelt.py
if-Bedingung in Python
In Python gibt es die Möglichkeiten Bedingungen zu überprüfen und entsprechend im
Programmablauf darauf zu reagieren. Hier könnten wir abhängig von der Uhrzeit den Nutzer
entsprechend Begrüßen. Aber erst einmal der allgemeine Aufbau von if -Abfragen und wie
wird diese einsetzen.
Und nun das Ganze als Python-Programm, in der wir als Erstes die Variable definieren:
wert = 3
if wert < 5:
print('Wert ist kleiner als 5')
Das wichtige ist, dass nach der if -Abfrage das weitere, was zu der if -Abfrage gehört,
eingerückt wird! Diese Einrückungen sind der Dreh- und Angelpunkt in Python und garantiert
einen sauberen Quellcode. Pfuscht man bei den Einrückungen, funktioniert das Programm
nicht wie erwartet.
Bei unserer if -Anfrage gehört alles Folgende, was eingerückt ist, zu der Bedingung. Und das
kann mehr als eine Zeile sein!
wert = 3
if wert < 5:
print('Wert ist kleiner als 5')
print('Ich gehöre auch noch zu der Bedingung')
print('und hier geht es nach der if-Abfrage weiter')
Lassen wir das Programm ausführen, erhalten wir als Ergebnis alle 3 Zeilen ausgegeben. Die 2
Textzeilen, die „innerhalb“ der if -Abfrage sind (sprich, die eingerückt sind) und die letzte
Textzeile, die nach der if -Abfrage kommt und nicht eingerückt ist.
Ändern wir nun unsere Variable am Anfang auf wert = 9" , erhalten wir bei der
Programmausführung nur noch die letzte Zeile ausgegeben, die nach der if -Abfrage kommt.
Die if -Abfrage ist nicht wahr, weil der Wert mit 9 bereits größer ist als die Bedingung < 5
und somit das eingerückte der if -Abfrage nicht ausgeführt wird.
Was passiert eigentlich genau bei wert < 5 ? Python überprüft, ob das Ergebnis wahr oder
falsch ist. Dabei kann auch direkt „true“ oder „false“ der if -Abfrage präsentiert werden und
diese reagiert darauf entsprechend:
if True:
print('if-Bedingung ist wahr')
Natürlich könnten wir auch eingeben if false: und es würde nichts angezeigt werden, da
unsere if -Abfrage nicht wahr ist.
Natürlich würde kein Mensch so eine if -Abfrage erstellen, denn die if -Abfrage würde ja
immer exakt zum gleichen Ergebnis führen. Allerdings können wir auch Variablen übergeben,
die diesen Wert haben.
wahroderfalsch = True
if wahroderfalsch:
print('if-Bedingung ist wahr')
Unsere Variable "wahroderfalsch" hat nun den Wert "true" zugewiesen bekommen und die if -
Abfrage reagiert entsprechend darauf.
Diese Variablen sind vom Typ Boolean – es gibt nur die Werte true oder false bei
Boolean. Diese Variablen-Typen sind benannt nach dem Erfinder George Boole.
Ungleich != in Python
Oft möchte man auch einfach wissen, ob eine bestimmte Bedingung nicht zutrifft, also
ungleich ist.
Als Beispiel wollen wir von einer Stundenzahl wissen, ob es NICHT 12 Uhr ist. Dazu unser
Code:
wert = 11
if wert != 5:
print('Es ist nicht 12 Uhr')
wert = 9
if wert < 5:
print('Wert ist kleiner als 5')
if wert > 4:
print('Wert ist größer als 4')
Dies wollen wir kürzer, da die zweite if -Abfrage einfach das Gegenteil gerade von der ersten
darstellt. Alles was nicht kleiner ist als 5 ist auf jeden Fall größer als 4. Und hier kommt das
schöne Wort else zum Einsatz:
wert = 9
if wert < 5:
print('Wert ist kleiner als 5')
else:
print('Wert ist größer als 4')
© https://www.python-lernen.de/if-abfrage-python.htm Seite 117
Unseren zweiten Part ersetzen wird durch else: . Trifft unsere if -Abfrage nicht zu, sprich
ist diese nicht wahr, sondern falsch, dann wird der Block unter else: ausgegeben:
Alle Vergleichs-Operatoren
Je nach Aufgabenstellung den passenden Vergleich nutzen!
== gleich
!= ungleich
< kleiner
> größer
Dazu brauchen wir eine Abfrage innerhalb der Abfrage. Und dazu kennt Python den Befehl
elif . In den meisten anderen Programmiersprachen kennt man dies als „elseif“ aber in
Python ist es elif .
wert = 9
if wert < 5:
print('Wert ist kleiner als 5')
elif wert == 5:
print('Wert ist exakt 5')
else:
print('Wert ist größer als 5')
Der Überprüfung von der Bedingung hinter elif wird nur dann überprüft, wenn die erste
Bedingung nicht zutrifft. Trifft unsere Bedingung unter elif auch nicht zu, dann kommt die
Alternative unter else zum Tragen.
wert = 9
if wert < 5:
print('Wert ist kleiner als 5')
elif wert = 5:
print('Wert ist exakt 5')
else:
print('Wert ist größer als 5')
Wir überprüfen bei elif , ob dieses exakt 5 entspricht. Hier ist der Standardfehler, dass
versehentlich nur ein Gleichzeichen (anstelle von 2) gemacht wurde. Das ist aber nicht möglich
und somit kommt eine Fehlermeldung von Python in Form von „SyntaxError: invalid syntax“
import random
Über die Hilfeanweisung erhalten wir die ersten Informationen zu verfügbaren Methoden der
Anweisung random .
print(help(random.random))
help(random.random)
print(random.random())
Bei jeder Ausgabe erfolgt eine andere Zahl – das ist das Wesen des Zufalls.
>>> print(random.random())
0.1229030667914014
>>> print(random.random())
0.4683265429999067
>>> print(random.random())
0.5755756960623487
© https://www.python-lernen.de/zufallszahlen-random.htm Seite 120
def zufallszahl():
return random.random() * 9 + 1
print (zufallszahl())
help(random.uniform)
Wir bekommen über random.uniform eine zufällige Nummer zwischen „a“ und „b“
zurückgeliefert.
print(random.uniform(5,8))
print(random.normalvariate(5, 0.1))
print(random.randint(1,6))
Wir bekommen nur ganzzahlige Werte wie bei einem normalen 6-seitigen Würfel zurück
zwischen eins und sechs (inklusive der Sechs).
for i in range(15):
print(random.randint(1,6))
Wir erstellen also als Erstes eine Liste mit unseren 3 Elementen:
print(random.choice(handgeste))
Das Modul random bietet noch weitere Möglichkeiten, die einem über
print(dir(random)) angezeigt werden. Für die meisten Anwendungen reichen die bisher
vorgestellten aus.
Somit haben wir schon eine schöne Möglichkeit für die zufällige Auswahl der Handgeste. Im
folgenden Kapitel bauen wir unser Spiel zusammen.
© https://www.python-lernen.de/uebung-lobesreden.htm Seite 122
Das gewünschte Ergebnis: ein sich immer änderndes Lob ausgeben in der Form:
„Du bist der ADJEKTIV NOMEN“
Beispielsweise:
„Du bist der beste Freund“
„Du bist der liebenswürdigste Mensch“
Was benötigen wir? Natürlich haben wir die jetzt benutzten Funktionen und Vorgehensweisen
bei Python schon in den letzten Kapiteln kennengelernt. Am besten ist natürlich nicht einfach
den später folgenden Code abzutippen, sondern erst einmal selber probieren, eine Lösung zu
erstellen.
wir haben beliebige viele positive Adjektive (die Liste kann beliebig erweitert werden):
beste
liebenswürdigste
schönste
größte
Mensch
Hecht
Freund
Kumpel
Programmierer
Aus diesen 2 Listen können wir nun eine Ausgabe auf dem Bildschirm durch Zufall erzeugen
lassen. Beispiele dazu, die können kommen:
Du bist …
Aufgabe: Lobesprogramm
Wir benötigen also in Python die Möglichkeit,
Unbedingt selber probieren. Dadurch lernt man am schnellsten (auch aus den unter
Umständen gemachten Fehlern).
Lösungsweg: Lobesprogramm:
Probiert und zu einem Ergebnis gekommen? Hier eine Lösung für unser Lob-Programm.
Im ersten Schritt erstellen wir 2 Listen. Variablen wären hier unpraktisch, da wir ja viele
ähnliche Wörter haben, uns später per Zufall aus den Listen auswählen wollen:
Und jetzt können wir auch gleich eine zweite Liste mit den Nomen machen:
Ab jetzt benötigen wir den Zufall. Dazu müssen wir das Modul random importieren. Das muss
gleich am Anfang unseres Python-Programmes geschehen. Muss ist übertrieben. Es muss
importiert sein, bevor es eingesetzt wird. Allerdings ist guter Stil am Anfang von einem Python-
Programm alle Module zu importieren.
import random
adjektive = ["beste", "liebenswuerdigste", "schoenste", "groesste"]
nomen = ["Mensch", "Hecht", "Freund", "Kumpel", "Programmierer"]
print ("Du bist der ")
Und nun wollen wir eine zufällige Auswahl. Diese erhalten wir über random und choice :
import random
adjektive = ["beste", "liebenswuerdigste", "schoenste", "groesste"]
nomen = ["Mensch", "Hecht", "Freund", "Kumpel", "Programmierer"]
print ("Du bist der ")
print (random.choice(adjektive))
print (random.choice(nomen))
Du bist der
beste
Freund
© https://www.python-lernen.de/uebung-lobesreden.htm Seite 124
Die Ausgabe kommt bereits, allerdings untereinander. Also nutzen wir nur 1 print und unser
Schmeichelprogramm ist fertig. Dies einmal nach dem Aufstehen ausführen und die Stimmung
ist mindestens um 3,5 Prozent besser:
import random
adjektive = ["beste", "liebenswuerdigste", "schoenste", "groesste"]
nomen = ["Mensch", "Hecht", "Freund", "Kumpel", "Programmierer"]
print ("Du bist der " +
random.choice(adjektive) +
" " +
random.choice(nomen)
)
Kleine Anmerkung am Rande. Es wurde in der fertigen Lösung noch ein Leerzeichen in der
Ausgabe zwischen dem Adjektiv und dem Nomen ausgegeben. Die print -Ausgabe ist im
obigen Code umgebrochen, um besser lesbar zu sein. Diese könnte auch komplett in einer
Zeile im Programmcode stehen.
Wie sieht eine while -Schleife in Python aus? Wieder benötigen wir eine Bedingung, die wir
bereits im Kapitel zu if -Bedingungen kennengelernt haben. Anhand dieser wird kontrolliert,
ob die Schleife weiter „ihre Kreise“ ziehen darf – die Bedingung wird kontrolliert, ob diese noch
richtig ist (sprich wahr ist). Ist die Bedingung nicht mehr wahr, wird die while -Schleife nicht
mehr ausgeführt und das Programm läuft nach der Schleife weiter bis zum Ende des
Programmcodes (wenn nach der Schleife noch Code kommt).
Im Vorfeld brauchen wir eine Variable, welche die Durchgänge zählt. Diese kontrollieren wir, ob
diese kleiner 11 ist (damit wir 10 Durchgänge bekommen).
durchgang = 1
while durchgang < 11:
print(durchgang)
print("nach der Schleife")
Wir sehen nun die Schleife und den typischen Aufbau mit der Einrückung. Alles was eingerückt
wird, gehört in den Schleifenkörper und wird bei jedem Schleifendurchgang durchlaufen.
Allerdings läuft das obige Programm unendlich lang. Warum? Unsere Variable „durchgang“ ist
immer unter 11, denn es ändert sich ja nichts an der Höhe der Zahl in der Variablen
„durchgang“. Zum Abbrechen hilft ctrl + c
Daher müssen wir unbedingt im Schleifenkörper die Zahl bei jedem Durchgang um 1 erhöhen.
Es muss also noch integriert werden durchgang = durchgang + 1 . Und auch dieser
Python-Code muss eingerückt in den Schleifenkörper, sonst wird dieser nicht als Bestand der
Schleife ausgeführt!
durchgang = 1
while durchgang < 11:
print(durchgang)
durchgang = durchgang + 1
print("nach der Schleife")
Lassen wir nun unser Python-Programm ablaufen, erhalten wir folgende Ausgabe:
1
2
3
4
5
6
7
8
9
10
nach der Schleife
© https://www.python-lernen.de/while-schleife.htm Seite 126
Hat die Variable dann den Wert 11, ist die Bedingung durchgang < 11 unwahr (false) und
die Schleife wird verlassen und die Ausgabe „nach der Schleife“ erfolgt.
So einfach sind Schleifen umsetzbar. Angebracht ist, dass die Bedingung irgendwann auch
„False“ annehmen kann, sonst läuft die Schleife unendlich lang (bis man das Kommando-
Fenster schließt oder den Computer ausschaltet).
© https://www.python-lernen.de/uebung-zahlenraten.htm Seite 127
Unser Zahlenraten-Spiel: der Computer bestimmt durch Zufall eine Zahl zwischen 0 und 100.
Wir haben 7 Versuche, exakt diese Zahl zu erraten. Bei jedem Rateversuch bekommen wir eine
der folgenden 3 möglichen Reaktionen von unserem Spiel:
Zusätzlich müssen wir neben der Zahl auch noch die Anzahl der Runden kontrollieren. Unsere
while -Schleife läuft maximal siebenmal durch.
durchgang = 0
while durchgang < 7:
print(durchgang)
durchgang = durchgang + 1
print("nach der Schleife")
Wir benötigen natürlich die Möglichkeit die Schleife vorzeitig zu beenden. Dies können wir über
die Anweisung break in einer if -Abfrage erreichen. Im folgenden Beispiel brechen wir bei 3
ab – im Spiel brechen wir ab, wenn der Spieler der Zahl erraten hat.
durchgang = 0
while durchgang < 7:
print(durchgang)
durchgang = durchgang + 1
if (durchgang == 3):
break
print("nach der Schleife")
durchgang = 0
aktiv = True
while aktiv:
print(durchgang)
durchgang = durchgang + 1
if (durchgang == 3):
aktiv = False
print("nach der Schleife")
© https://www.python-lernen.de/uebung-zahlenraten.htm Seite 128
Was ist nun der große Vorteil von der zweiten Variante? Ich kann auf Benutzereingaben
reagieren und beschränke die Anzahl der Schleifendurchläufe nicht im Vorfeld. Nehmen wir an,
der Benutzer kann das Programm beenden mit der Eingabe von „ende“. Somit können wir
zusätzlich die Benutzereingabe kontrollieren und sobald vom Benutzer „ende“ eintippt wird,
setzen wir den Inhalt der Variable „aktiv“ auf „False“ und das Programm wird beendet:
durchgang = 0
aktiv = True
while aktiv:
print(durchgang)
durchgang = durchgang + 1
benutzereingabe = input("Bitte Zahl eingeben: ")
if (benutzereingabe == "ende"):
aktiv = False
print("nach der Schleife")
Wichtig ist, dass wir hier Python3 nutzen. Ansonsten bekommen wir eine Fehlermeldung bei
Python2.
Aufgabe: Zahlenratespiel
Der Spieler hat 7-mal die Chance die vom Computer durch Zufall festgelegte Zahl zu erraten.
Als Rückmeldung bekommt er nur:
Wenn der Spieler gewonnen hat, kommt eine entsprechende Meldung. Hat der Spieler die Zahl
nicht erraten, kommt als Nachricht: „Schade – verloren. Einfach nochmals probieren“.
Bitte erst selber eine Lösung probieren, bevor die folgende Lösung kommt. Alle benötigten
Python-Befehle wurden in den vorherigen Kapiteln vorgestellt.
Lösung: Zahlenratespiel
Sehr oft wird man am Anfang beim Programmieren über die Umwandlung von den Inhalten der
Variablen stolpern. Wir wollen einen Vergleich zwischen der Nutzereingabe und einer Zahl
machen. Also müssen wir eine Umwandlung über int machen. Wenn wir am Spielende die
vom Computer erstellte Zahl ausgeben wollen, müssen wir die Zahl für die Ausgabe dann
umwandeln anhand von var .
Hier nun eine mögliche Lösung (und immer daran denken: es gibt mehr als einen Weg nach
Rom):
© https://www.python-lernen.de/uebung-zahlenraten.htm Seite 129
import random
durchgang = 0
aktiv = True
ratezahl = random.randint(0,100)
while aktiv:
durchgang = durchgang + 1
print() # für Abstand (nur Optik)
print(durchgang)
benutzereingabe = int (input("Bitte Zahl eingeben: "))
if benutzereingabe == ratezahl:
print("Gewonnen! Die geheime Zahl ist nicht mehr geheim")
aktiv = False
break
elif benutzereingabe > ratezahl:
print("deine geratene Zahl ist zu groß")
else:
print("deine geratene Zahl ist zu klein")
if (durchgang == 7):
print("Schade – verloren. Einfach nochmals probieren")
print("Es war die Zahl " + str(ratezahl))
aktiv = False
print("Ende des Spiels")
© https://www.python-lernen.de/for-schleife.htm Seite 130
Schauen wir uns den Aufbau und die Möglichkeiten der for -Schleife an. In Python ist die
for -Schleife mit Listen eng verbunden. Daher sollte man sich das Kapitel mit Listen bereits
zu Gemüte geführt haben.
Die for -Schleife durchläuft eine vorgegebene Liste und wir können direkt die Einzelwerte der
Liste verwenden.
Die Vornamen-Liste soll nun über die for-Schleife durchlaufen werden und jeder Einzelwert
ausgegeben werden.
Axel
Elke
Martin
nach der for-Schleife
Bemerkenswert ist der große Unterschied der for -Schleife zu anderen Programmiersprachen.
Allerdings ist der Aufbau sehr geschickt, sobald man sich daran gewöhnt hat. Kennt man keine
andere Programmiersprache, dann ist die Anwendung der for -Schleife sehr einfach zu
verstehen.
Im Klartext ausgedrückt wäre die for -Schleife: solange es Einzelwerte in der Liste
„vornamen“ gibt, durchlaufe die Schleife (sprich den eingerückten Bereich danach). Dort stehen
dann in der Variablen „einzelwert“ der in diesem Durchlauf aktuelle Wert der Liste zur
Verfügung.
Im ersten Durchgang wird in der Liste „vorname“ als Wert „Axel“ ausgelesen und in die Variable
„einzelwert“ eingetragen. Diese lassen wir dann im Inneren der Schleife über
print(einzelwert) ausgeben.
Dann überprüft Python, ob ein weiterer Wert in der Liste „vornamen“ vorhanden ist. Das ist der
Fall. Somit läuft die Schleife eine zweite Runde und die Variable „einzelwert“ wird durch den
Wert „Elke“ überschrieben, die dann ausgegeben wird.
Im dritten Durchgang überprüft Python wieder, ob ein weiterer Wert in der Liste „vornamen“
vorhanden ist. Das ist der Fall – wieder wird die Variable „einzelwert“ mit dem Wert „Martin“
überschrieben und im Schleifenkörper ausgegeben.
© https://www.python-lernen.de/for-schleife.htm Seite 131
Wieder überprüft Python, ob ein weiterer Wert in der Liste vorhanden ist. Dies ist nach den
ersten 3 Werten nicht mehr der Fall. Unsere Liste verfügt nur über diese 3 Werte. Die for -
Schleife ist beendet.
Dabei ist es egal, ob in der Liste Zeichenketten oder Zahlen oder ein Mischmasch steht.
Wir haben mit dem letzten Beispiel eine gemischte Liste mit Zahlen (Integer) und
Zeichenketten (String). Daher müssen wir darauf achten, was wir mit den Ergebnissen
anstellen. Mit den Zahlen könnten wir zwar rechnen, aber nicht mit den Strings. Da ist einfach
gesunder Menschenverstand angesagt, was man mit den zur Verfügung stehenden Variablen
und Inhalten so treibt.
if -Abfragen in Schleifen
Wir können auch if -Abfragen in Schleifen einbauen. Dann wird die Einrückung entsprechend
tiefer und bei jedem Durchlauf wird diese if -Bedingung überprüft. In unserem Beispiel wollen
wir schauen, ob der Wert z.B. „Axel“ ist und entsprechend darauf reagieren.
Jetzt gehen wir in die for -Schleife und überprüfen mit folgender if -Abfrage:
if einzelwert == "Axel"
print("Ich")
else
print(einzelwert)
Nun müssen wir beide Programmteile zusammenbringen. Hier ist nur die Schachtelung wichtig
und dass entsprechend eingerückt wird. Unsere if -Abfrage muss also tiefer eingerückt
werden, da diese ja in den Schleifenkörper von unserer for -Schleife muss:
Ich
Elke
Martin
nach der Schleife
Ja, ja ich weiß – der Esel nennt sich immer zuerst (aber woher kommt dieses Sprichwort?).
© https://www.python-lernen.de/for-schleife.htm Seite 132
# aufwendige Konstruktion
nummer = 0
for einzelwert in vornamen:
print(nummer, einzelwert)
nummer += 1
0 Axel
1 Elke
2 Martin
Und genau so einen Chatbot wollen wir mit Python programmieren. Dazu brauchen wir die
grundlegende Funktionsweise.
Listen
Dictionary
while-Schleifen
for-Schleifen
Funktionsweise Chatbot
© https://www.python-lernen.de/chatbot-programmieren.htm Seite 134
Der Nutzer wird vom Chatbot begrüßt und gleich aufgeklärt, dass er die Unterhaltung mit „bye“
beenden kann. Dann wird auf die Nutzereingabe gewartet.
Liegt die Nutzereingabe vor, wird dir dieser Satz in Einzelteile (sprich Wörter) zerlegt.
Dann wird überprüft, ob Einzelwörter in der Datenbasis vorkommen, die als „passende“ Antwort
vorliegen.
Wenn eine „passende“ Antwort vorliegt, wird diese als Feedback ausgegeben.
Liegt keine passende Antwort vor, wird eine zufällige Antwort vom Chatbot zurückgegeben, um
das Gespräch aufrechtzuerhalten.
Diesen Ablauf werden wir nun Schritt für Schritt in Python programmieren. Dazu werden wir alle
bisher gelernten Elemente von Python nutzen.
© https://www.python-lernen.de/chatbot-programmieren.htm Seite 135
Schritt 1: Eingabe mit Schleife bis zu dem Beenden durch den Benutzer
Im ersten Schritt wollen wir nach der Begrüßung unsere Nutzer zur Eingabe eines Textes
auffordern.
Bevor wir nun mit deutschen Texten arbeiten, in denen immer wieder Umlaute wie „öäü“
vorkommen können (egal ob bei der Eingabe oder bei der Ausgabe), sollten wir Python darauf
vorbereiten. Wir speichern unsere Datei mit dem UTF-8 Encoding ab. Daher teilen wir das auch
Python mit. Diese geschieht über:
Wichtig ist, dass dies in der ersten Zeile unseres Programm-Codes geschieht. Wer mehr
darüber lesen will, kann einfach mal „Encoding Cookies Python“ in eine Suchmaschine
eingeben
Es gibt noch weitere Codings, die hier nicht weiter aufgeführt werden.
Jetzt begrüßen wir unsere Nutzer und geben einen Hinweis, wie das Programm auch wieder
beendet werden kann:
Wir wollen jetzt die Texteingabe des Nutzers erfassen. Diese wird in der Variable
„ nutzereingabe “ gespeichert und zur Kontrolle auf dem Bildschirm ausgegeben:
Sollte jetzt eine Fehlermeldung in Form eines „NameError“ kommen, dann bitte sicherstellen,
dass wir auch eine aktuelle Python-Version (mindestens Python ab Version 3) verwenden! Bei
den alten Python2-Versionen wird der Anweisung input() anders gehandhabt. Bei Python3
wird die Eingabe als String verarbeitet.
Wie man in unserem Ablaufdiagramm sieht, soll der Nutzer immer weitere Eingaben machen
können, bis dieser die Eingabe „bye“ zum Beenden eintippt.
Wir benötigen 2-mal die Anweisung nutzereingabe = "" . Die erste Anweisung initialisiert
die Variabel „ nutzereingabe “ und die zweite leert einen eventuell vorhandenen Inhalt, was
© https://www.python-lernen.de/chatbot-programmieren.htm Seite 136
Wenn wir unser Programm nun testen, können wir etwas eingeben und dieses wird einfach
wieder ausgegeben. Allerdings können wir auch nichts eingeben und einfach nur die Eingabe
mit der Return-Taste leer übergeben. Das ist natürlich wenig hilfreich für den folgenden
Programmablauf. Daher sollten wir noch sicherstellen, dass eine leere Eingabe nicht möglich
ist und der Benutzer weiter gefragt wird. Also bauen wir in unsere while -Schleife eine zweite
while -Schleife, die eine Eingabe sicherstellt.
zufallsantworten=["Oh, wirklich", "Interessant ...", "Das kann man so sehen", "Ich verstehe ..."
Da wir das random-Modul für eine zufällige Antwort benötigen, binden wir das am Anfang
unseres Programms ein (wie auch unsere Liste mit den möglichen zufälligen Antworten).
Hier eine kleine Auswahl – je größer, desto besser für die Unterhaltung. Unser Dictionary
packen wir auch an den Anfang unseres Programms.
Jetzt müssen wir überprüfen, ob ein Stoppwort in der Nutzereingabe vorkommt. Um nicht
Probleme mit Groß- und Kleinschreibung zu haben, setzen wir die Eingabe komplett in
Kleinbuchstaben um
nutzereingabe = nutzereingabe.lower()
nutzerwoerter = nutzereingabe.split()
Diese Liste können wir Wort für Wort durchgehen und wenn ein Wort in den Stoppwörtern
auftaucht, diese mögliche Antwort nutzen:
Wichtig ist hier die Anwendung von dem unscheinbaren Python-Befehl in . Wir überprüfen, ob
Wörter aus unserer Liste „einzelwoerter“ innerhalb unseres Wörterbuches „reaktionsantworten“
als Keys vorkommen. Als Rückantwort erhalten wir ein „True“ wenn vorhanden bzw. ein „False“
wenn nicht vorhanden. Dies bewirkt die obige Anweisung:
if einzelwoerter in reaktionsantworten:
Wir müssen uns nur merken, dann eine „passende“ Antwort gefunden wurde. Ansonsten muss
© https://www.python-lernen.de/chatbot-programmieren.htm Seite 138
eine zufällige Antwort ausgewählt werden. Das speichern wir über „intelligenteAntworten =
True“, die am Anfang auf „False“ gesetzt werden muss.
Diese können wir nun abfragen und dann unsere zufällige Antwort ausgeben:
zufallsantworten=["Oh, wirklich", "Interessant ...", "Das kann man so sehen", "Ich verstehe ..."
nutzereingabe = ""
while nutzereingabe != "bye":
nutzereingabe = ""
while nutzereingabe == "":
nutzereingabe = input("Ihre Frage/Antwort: ")
nutzereingabe = nutzereingabe.lower()
nutzerwoerter = nutzereingabe.split()
intelligenteAntworten = False
for einzelwoerter in nutzerwoerter:
if einzelwoerter in reaktionsantworten:
print(reaktionsantworten[einzelwoerter])
intelligenteAntworten = True
if intelligenteAntworten == False:
print(random.choice(zufallsantworten))
print("")
print("Einen schönen Tag wünsche ich Dir. Bis zum nächsten Mal")
Das war ein sehr einfacher Chatbot in Python. Dieser kann natürlich noch ausgefeilt werden.
© https://www.python-lernen.de/range-listen-mit-werten-erstellen.htm Seite 139
Über die Funktion range können wir eine Liste erstellen, die von einem vorgegebenen Wert
bis zu einem vorgegebenen Wert geht.
werte = list(range(3))
print(werte)
[0, 1, 2]
Anmerkung: bei der alten Python-Version reichte der folgende Code noch aus: werte =
range(3) – aber bitte nur mit aktueller Python-Version arbeiten (und vor allem Python
lernen)!
Der Wert startet bei 0 und zählt dann 3 Zahlen hoch. Wir kommen also bei einer Zahl eins
kleiner als unser vorgegebener Endwert raus.
Die range -Funktion können wir nun in den aus dem vorherigen Kapitel eingesetzten for -
Schleifen nutzen:
0
1
2
Somit wird die for -Schleife deutlich „ähnlicher“ wie auch anderen Programmiersprachen
diese einsetzen. Aber die Umsetzung in Python ist deutlich clever, da diese sehr flexibel ist.
werte = list(range(2,8))
print(werte)
werte[2,3,4,5,6,7]
© https://www.python-lernen.de/range-listen-mit-werten-erstellen.htm Seite 140
Hier sieht man bei der Aussage von vorher, dass „3-Zahlen ab 0“ so nicht ganz richtig ist. Bei
der range -Funktion wird eins kleiner als die „Endzahl“ genutzt. Im Beispiel haben wir 8
angegeben und erhalten in der erstellten Liste dann als letzte und größte Zahl 7.
werte = list(range(2,8,2))
print(werte)
werte[2, 4, 6]
Die 8 bei range(2,8,2) ist raus, da ja nur „Endwert-1“ bei range genutzt wird.
Es können auch negative Schrittweiten angegeben werden. Dazu muss der Startwert größer als
der Endwert sein:
werte = list(range(12,8,-1))
print(werte)
Das Ganze geht natürlich auch ins Minus, wenn das bei den End- bzw. Anfangswerte
angegeben wurde:
werte = list(range(3,-3,-1))
print(werte)
Bei einem Lotto-Simulator mit einer Ziehung von 6 Zahlen aus 49 möglichen Zahlen darf keine
Zahl doppelt vorkommen. Wäre sonst sehr merkwürdig. Daher fällt dafür die Methode über
random.randint(1, 50) aus. Man könnte damit auch eine Umsetzung einer Simulation
der Ziehung von Lottozahlen programmieren – nur der Aufwand ist deutlich zu hoch (genau
aus dem Problem der eventuell doppelten Zahlen).
Also erstellen wir uns als Erstes eine Liste aller möglichen Zahlen über range(1,50) . Als
Start beginnen wir bei 1 und lassen range bis 50 laufen – was bewirkt, dass wir alles Zahlen
von 1 bis einschließlich 49 bekommen.
Für die Zufallsfunktion nutzen wir sample() . Hier wird in der Klammer die Liste und die
gewünschte Anzahl angegeben:
lottozahlen_gewinner = random.sample(lottozahlen_alle, 6)
Bevor man die unten folgenden Schritt für Schritt Lösung liest, bitte selber testen! Es gibt auch
mehrere Wege nach Rom. Es muss nicht unbedingt sample() genutzt werden.
lottozahlen_alle = []
Diese Liste erweitern wir über extend . Hier bitte nicht auf die Python-Anweisung append
hereinfallen.
lottozahlen_alle = []
lottozahlen_alle.extend(range(1,50))
print(lottozahlen_alle)
Ab jetzt gibt es mehrere Möglichkeiten ans Ziel. Benutzen wir als Erstes die einfachste. Python
soll uns einfach 6 Einträge aus unserer Liste aller Lottozahlen per Zufall auswählen. Dazu gibt
es die Anweisung sample() . Diese Anweisung ist in dem Modul random integriert – sprich
wir müssen dieses am Anfang unseres Python-Programmes importieren!
Wir lassen das Ergebnis von sample() einer neuer Liste mit dem Namen
„lottozahlen_gewinner“ zuweisen.
import random
lottozahlen_alle = []
lottozahlen_alle.extend(range(1,50))
lottozahlen_gewinner = random.sample(lottozahlen_alle, 6)
print(lottozahlen_gewinner)
Es fällt auf, dass wir eine wild gemischte Liste erhalten. Erst einmal erstaunlich, da die
ursprüngliche Gesamtliste „lottozahlen_alle“ aufsteigend sortiert ist.
import random
lottozahlen_alle = []
lottozahlen_alle.extend(range(1,50))
lottozahlen_gewinner = random.sample(lottozahlen_alle, 6)
lottozahlen_gewinner.sort()
print(lottozahlen_gewinner)
Wichtig ist: Es ist keine Zahl doppelt! Das ist der große Unterschied zu dem Einsatz von
choices() . Der Vollständigkeit halber hier auch eine Ausgabe damit. Bei dieser Anweisung
muss über „k=6“ die gewünschte Anzahl mitgegeben werden.
import random
lottozahlen_alle = []
lottozahlen_alle.extend(range(1,50))
lottozahlen_gewinner = random.sample(lottozahlen_alle, 6)
lottozahlen_gewinner.sort()
print(lottozahlen_gewinner)
print(random.choices(lottozahlen_alle, k=6))
Das Ergebnis:
Die erste Zeile kommt von sample() und die zweite Zeile von choices() . In der zweiten
Zeile ist dir 32 doppelt. Einfach einmal testen.
import random
lottozahlen = []
lottozahlen.extend(range(1,50))
random.shuffle(lottozahlen)
for x in range(6):
print(lottozahlen[x])
Wir haben eine for -Schleife, die die Zahlen von 0 bis 9 durchläuft. Diese soll aber bei
Erreichen von der Zahl 7 abbrechen und nach der Schleife weitermachen.
0
1
2
3
4
5
6
Schleifenabbruch wird erzwungen
Nach der Schleife
Dies wird in einem Beispiel klarer. Wir wollen beispielsweise nur gerade Ergebnisse ausgeben
lassen. Dazu wird die mathematische Funktion des Modulo genutzt.
Was macht der Modulo? Diese gibt uns als Rückantwort entweder 0 für gerade oder 1 für
ungerade zurück. Der Modulo wird über die Konstruktion " %2 " aktiviert. Schauen wir Beispiele
dazu an:
wert = 3
print(wert%2)
Hier erhalten wir als Ausgabe dann 1. Die Zahl 3 ist ungerade und somit kommt als Ergebnis
dann 1.
wert = 4
print(wert%2)
Hier erhalten wir als Rückgabe die 0, da unsere Zahl 4 gerade ist.
© https://www.python-lernen.de/break-continue-schleifen-ablauf.htm Seite 144
wert = 13
print(wert%2)
Die Zahl 13 ist ungerade und somit liefert der Modulo als Rückgabe 1.
Setzten wir dieses Wissen nun in unsere for -Schleife ein, damit nur noch gerade Zahlen
ausgegeben werden und die Schleife in diesem Durchgang nicht weiter durchlaufen wird.
Als Ausgabe erhalten wir alle geraden Zahlen (ohne 10, da ja der Durchgang nur bis 9 geht)
0
2
4
6
8
Nach der Schleife
Dies waren beide Möglichkeiten, eine Schleife komplett abzubrechen ( break ) oder den
Schleifendurchlauf zu überspringen ( continue ).
Das klappt sowohl bei der for -Schleife wie auch bei der while -Schleife.
© https://www.python-lernen.de/hangman-python-programmieren.htm Seite 145
Liste
while -Schleife
for -Schleife
in
Wir benötigen wieder für unser Spiel den Zufall, daher können wir gleich am Anfang unseres
Codes das random -Modul importieren:
import random
Natürlich benötigen wir noch Wörter, aus denen unser Programm dann per Zufall auswählen
kann für das Ratespiel. Bisher haben wir Listen immer der folgenden Form aufgebaut:
Einfacher (vor allem für später, wenn die Wörter über eine Datei geladen werden) ist die
Anweisung split() . Diese erzeugt aus einem String eine Liste.
Dieser Aufruf von split() ohne einen Parameter erledigt für uns schon unsere Aufgabe. Der
Vollständigkeitshalber: als Parameter kann das verwendete Trennzeichen angegeben werden.
Soll Beispielsweise anhand von „@“ getrennt werden, erhalten wir bei einer E-Mail-Adresse
sofort den Domainnamen extrahiert.
mailaufgeteilt = 'mailadresse@pyhton-lernen.de'.split('@')
Zusätzlich kann eine Anzahl mitgegeben werden, wie groß die erzeugte Liste werden soll.
beispiel = 'Wort1#Wort2#Wort3'.split('#', 2)
Zurück zu unserem Spiel. Zum Entwickeln nutzen wir übersichtliche Anzahl von 5 Wörter – es
geht hier um das Prinzip. Die Anzahl der Wörter kann später ja beliebig erweitert werden.
import random
print("hangman in Python")
woerter = 'Hund Katze Maus Haus raus'.split()
Wir benötigen nun aus unserer Liste ein zufälliges Wort. Dazu bietet uns die Anweisung
random.choice() die schnellste Möglichkeit.
Das zufällig ausgewählte Wort speichern wir in der Variable ratewort und lassen es zur
Kontrolle ausgeben. Bei jedem Programmaufruf sollte ein anderes kommen.
© https://www.python-lernen.de/hangman-python-programmieren.htm Seite 146
import random
print("hangman in Python")
woerter = 'Hund Katze Maus Haus raus'.split()
ratewort = random.choice(woerter)
print (ratewort)
Wir wollen für die einzelnen Buchstaben des Wortes nur Unterstriche ausgegeben bekommen.
Zusätzlich soll ein Leerzeichen nach dem Unterstrich kommen, damit es deutlich ist, wie viele
Buchstaben es sind.
Dazu entwickeln wir in 2 Schritten den entsprechenden Code. Erst das es wie gewünscht
ausgegeben wird und dann packen wir diesen Code in eine Funktion.
Wir durchlaufen die einzelnen Buchstaben unserer Variablen „ratewort“ und lassen zum Testen
jeden Buchstaben mit Leerzeichen danach ausgeben.
Für jeden Buchstaben soll als Bildschirmausgabe ein Unterstrich mit zusätzlichem Leerzeichen
ausgeben werden:
import random
print("hangman in Python")
woerter = 'Hund Katze Maus Haus raus'.split()
ratewort = random.choice(woerter)
print (ratewort)
# zum Test nur!
for buchstaben in ratewort:
print (buchstaben, " ")
Als Ergebnis erhalten wir die einzelnen Buchstaben jeweils in einer neuen Zeile.
hangman in Python
Katze
K
a
t
z
e
Von unserem Leerzeichen sehen wir nicht mehr viel. In der alten Python2-Version konnte man
noch mit einem Komma nach der print -Anweisung den Umbruch verhindern. Wir wollen
aber nicht mit einer alten Version arbeiten! Schaut man sich den Befehlsaufbau von print()
in der aktuellen Python Version an, können wir der Funktion print() noch weitere Parameter
mitgeben wie beispielsweise end=' ' oder in unserem Fall ein Unterstrich:
K _a _t _z _e _
Wenn wir nur die Unterstriche ohne Buchstaben wollen, dann können wir auch nur unseren
Parameter „missbrauchen“.
© https://www.python-lernen.de/hangman-python-programmieren.htm Seite 147
_ _ _ _ _
Legen wir dazu eine weitere Liste mit dem Namen erraten an. Diese wird am Anfang
unseres Python-Codes gemacht, damit alle Variablen und Listen-Bezeichnungen sofort
sichtbar sind:
import random
print("hangman in Python")
woerter = 'Hund Katze Maus Haus raus'.split()
erraten = []
ratewort = random.choice(woerter)
Bisher ist unsere Liste mit Leer. Also füllen wir diese vor unserer ersten Raterunde mit
Unterstrichen. Dazu durchlaufen wir mit der for -Anweisung unser durch Zufall bestimmtes
ratewort und werden für jeden einzelnen Buchstaben unsere Liste erraten mit einem
Eintrag „_“ ergänzen:
import random
print("hangman in Python")
woerter = 'Hund Katze Maus Haus raus'.split()
erraten = []
ratewort = random.choice(woerter)
for buchstaben in ratewort:
erraten.append('_')
Jetzt können wir übergehen, dass der Nutzer seine Eingaben machen kann.
Nutzereingabe in Schleife
Da unser Spiel auf jeden Fall über mehrere Runden läuft, benötigen wir eine Schleife. Diese
haben wir bereits im Kapitel zum Chatbot ( https://www.python-lernen.de/chatbot-
programmieren.htm ) kennengelernt. Der Nutzer hat auch immer die Möglichkeit das Spiel
vorzeitig zu beenden. Wieder brauchen wir eine Variable mit dem Namen nutzereingabe ,
die wir am Anfang festlegen. Und nun kommt unsere while -Schleife, bis entweder das Spiel
gewonnen oder verloren ist oder der Spieler abbricht.
© https://www.python-lernen.de/hangman-python-programmieren.htm Seite 148
import random
print("hangman in Python")
woerter = 'Hund Katze Maus Haus raus'.split()
erraten = []
nutzereingabe = ""
ratewort = random.choice(woerter)
for buchstaben in ratewort:
erraten.append('_')
while nutzereingabe != "bye":
nutzereingabe = input("Ihr Vorschlag: ")
Der Nutzer kann nun unendlich lange Vorschläge machen – noch wird weder etwas kontrolliert
noch ausgegeben.
Lassen wir vor der Nutzereingabe unseren bisherigen erraten Stand ausgeben (Unterstriche
und erratene Buchstaben) – also vor der ersten Runde nur Unterstriche.
Das print() benötigen wir, damit der Text „Ihr Vorschlag:“ in der nächsten Zeile kommt.
hangman in Python
_ _ _ _
Ihr Vorschlag:
Jetzt kann schon getestet werden und wir erhalten bei Übereinstimmung als
Bildschirmausgabe „Treffer“.
Jetzt ist es wichtig, einfach auch Großschreibung zu testen bzw. was passiert, wenn mehr als
1 Buchstaben durch den Spieler eingegeben wird.
Ergebnis:
Eine Eingabe von mehr als einem Buchstaben durch den Spieler läuft ins Leere. Dann hat der
Spieler Pech gehabt – damit können wir leben (zumal der Spieler auch „bye“ zum Spielabbruch
© https://www.python-lernen.de/hangman-python-programmieren.htm Seite 149
Großschreibung ist ein Problem – sowohl bei Eingabe des Spielers wie auch beim zu
erratendem Wort. Also vergleichen wir immer nur Kleinbuchstaben und wir sind aus dem
Problem raus.
import random
print("hangman in Python")
woerter = 'Hund Katze Maus Haus raus'.split()
erraten = []
nutzereingabe = ""
ratewort = random.choice(woerter)
for buchstaben in ratewort:
erraten.append('_')
while nutzereingabe != "bye":
for ausgabe in erraten:
print (ausgabe, end=' ')
print()
nutzereingabe = input("Ihr Vorschlag: ")
for buchstaben in ratewort:
if buchstaben.lower() == nutzereingabe.lower():
print ("Treffer")
Dazu brauchen wir noch eine Hilfsvariable „x“ um die Position des aktuellen Buchstabens in
der Liste zu kennen.
Diese Hilfsvariable wird bei jedem Durchlauf hochgezählt und bei einem Treffer wird der
Buchstabe in unserer Liste erraten an der entsprechenden Position eingetragen:
x = 0
for buchstaben in ratewort:
if buchstaben.lower() == nutzereingabe.lower():
print ("Treffer")
erraten[x] = buchstaben
x += 1
Spiel gewonnen?
Jetzt wollen wir kontrollieren, ob das Spiel gewonnen wurde. Dazu dürfen in unserer Liste
erraten keine Unterstriche mehr vorhanden sein. Diese Kontrolle läuft bei Listen sehr
einfach über die Python-Anweisung in .
# Kontrolle ob gewonnen
if '_' in erraten:
print('Noch nicht gewonnen')
else:
print("gewonnen")
© https://www.python-lernen.de/hangman-python-programmieren.htm Seite 150
Damit das Python-Programm bei gewonnenem Spiel beendet wird, müssen wir nur unsere
Schleife vorzeitig beenden. Das können wir über die Anweisung break erzwingen.
import random
print("hangman in Python")
woerter = 'Hund Katze Maus Haus raus'.split()
erraten = []
nutzereingabe = ""
ratewort = random.choice(woerter)
for buchstaben in ratewort:
erraten.append('_')
while nutzereingabe != "bye":
for ausgabe in erraten:
print (ausgabe, end=' ')
print()
nutzereingabe = input("Ihr Vorschlag: ")
x = 0
for buchstaben in ratewort:
if buchstaben.lower() == nutzereingabe.lower():
print ("Treffer")
erraten[x] = buchstaben
x += 1
print()
# Kontrolle ob gewonnen
if '_' in erraten:
print('Noch nicht gewonnen')
else:
print("gewonnen")
break
Spiel verloren?
Bisher können wir unendlich lange raten und habe nicht das Spiel verloren. Daher sollten wir
die Bedingung, wann das Spiel verloren ist einbauen. Verloren ist, wenn man 7-mal einen
falschen Tipp als Spiel abgibt. Diese Zahl führen wir in der Variabel fehlversuche mit. Auch
diese wird am Anfang festgelegt.
Innerhalb der Kontrolle, ob gewonnen nehmen wir die Kontrolle auf, ob verloren. Die Ausgabe
„Noch nicht gewonnen“ werden deaktiviert.
# Kontrolle ob gewonnen
if '_' in erraten:
# print('Noch nicht gewonnen')
fehlversuche -= 1
if fehlversuche == 0:
print("Schade - verloren!")
break
else:
print("gewonnen")
break
Und somit haben wir den kompletten Python-Programmcode für unser Galgenmännchen-Spiel.
© https://www.python-lernen.de/hangman-python-programmieren.htm Seite 151
import random
print("hangman in Python")
woerter = 'Hund Katze Maus Haus raus'.split()
erraten = []
nutzereingabe = ""
fehlversuche = 7
ratewort = random.choice(woerter)
for buchstaben in ratewort:
erraten.append('_')
while nutzereingabe != "bye":
for ausgabe in erraten:
print (ausgabe, end=' ')
print()
nutzereingabe = input("Ihr Vorschlag: ")
x = 0
for buchstaben in ratewort:
if buchstaben.lower() == nutzereingabe.lower():
print ("Treffer")
erraten[x] = buchstaben
x += 1
print()
# Kontrolle ob gewonnen
if '_' in erraten:
# print('Noch nicht gewonnen')
fehlversuche -= 1
if fehlversuche == 0:
print("Schade - verloren!")
break
else:
print("Gewonnen, das Wort war: ", ratewort)
break
© https://www.python-lernen.de/funktionen-in-python.htm Seite 152
Funktionen in Python
Bisher haben wir unsere Programmcode einfach von oben nach unten geschrieben und in
dieser Reihenfolge wurde dieser abgearbeitet. Jetzt kann es vorkommen, dass wir einige
Programmabläufe öfters benötigen. Beispielsweise wollen wir die Uhrzeit am Programmstart
und am Programmende ausgeben. Dazu müssten wir den gleichen Code also verdoppelt und
am Anfang und Ende unseres Programmes schreiben. Das bläht das Programm auf und bringt
unnötige Fehlerquellen. Hier helfende Funktionen.
Wir vergeben also einen Namen für unsere Funktion, die wir an jeder beliebigen Stelle in
unserem Python-Programm aufrufen können.
Hierzu wird eine Funktion definiert. Und genau dieses Schlüsselwort def erwartet Python
auch, wenn ein Funktionsname festlegt wird. Die typischen Klammern danach zeigen auch,
dass es sich um eine Funktion handelt. Aber definieren wir es eine Funktion. Die nichts
anderes macht, als die Textausgabe "Ausgabe von Text aus einer Funktion".
def ausgabe():
print("Ausgabe von Text aus einer Funktion")
print("Programm abgelaufen")
Rufen wir nun unser Programm auf, erhalten wir nur die Ausgabe:
Programm abgelaufen
Die neue Funktion mit dem Namen ausgabe selber wurde offensichtlich nicht ausgeführt,
sonst hätte eine weitere Textausgabe stattfinden müssen.
Zum Aufrufen einer Funktion benötigen wir den Funktionsnamen gefolgt von den runden
Klammern.
def ausgabe():
print("Ausgabe von Text aus einer Funktion")
ausgabe()
print("Programm abgelaufen")
Programm abgelaufen
© https://www.python-lernen.de/funktionen-in-python.htm Seite 153
Die Funktion können wir beliebig oft aufrufen. So können wir Code recyceln und sparen uns
Tipparbeit:
def ausgabe():
print("Ausgabe von Text aus einer Funktion")
ausgabe()
ausgabe()
print("Programm abgelaufen")
def ausgabe(wert1):
print("Ausgabe von Text aus einer Funktion")
print(wert1)
ausgabe(5)
ausgabe(5,3)
Jetzt kann man natürlich nach Belieben mit den vorhandenen Variablen arbeiten. Als Beispiel
lassen wir nun in der Funktion hinein 3 Werte übertragen und dann mit der Funktion eine for -
Ausgabe (siehe früheres Kapitel über for ) und entsprechender Schrittweite.
ausgabe(4, 9, 2)
ausgabe(-5, -8, -1)
print("habe fertig")
© https://www.python-lernen.de/funktionen-in-python.htm Seite 154
4
6
8
Funktion ausgabe durchlaufen
5
6
7
Funktion ausgabe durchlaufen
habe fertig
Somit sind wir deutlich flexibler bei der Ausgabe geworden. Je nach Anwendung ist der
Umfang innerhalb einer Funktion deutlich umfangreicher als unsere 3 Beispielzeilen. An der
Funktion und den Einsatzmöglichkeiten ändert sich dadurch nichts.
ausgabe(4, 9)
ausgabe(4, 9, 2)
4
5
6
7
8
Funktion ausgabe durchlaufen
4
6
8
Funktion ausgabe durchlaufen
Beim ersten Aufruf wird der Vorgabewert von 1 genommen und wir sparen Tipparbeit beim
Standardfall. Beim zweiten Aufruf wird die übergeben 2 als Schrittweite genutzt.
© https://www.python-lernen.de/funktionen-in-python.htm Seite 155
Wollen wir nun auch den Startwert für unsere for -Ausgabe auf 1 setzen, weil in unserem Fall
das sehr oft vorkommt, können wir das tun:
ausgabe(9)
Hier ist die übliche Vorgehensweise, dass Werte mit Vorgaben einfach rechts von den Werten
ohne Vorgaben stehen. Bauen wir unser Beispiel entsprechend um:
ausgabe(9)
Jetzt funktioniert unserer Funktion auch mit dem Aufruf von nur einer Angabe. Allerdings
müssen wir im Hinterkopf haben, dass nun die Reihenfolge des Funktionsaufrufs erst der
endwert, dann ein eventueller anfangswert (wenn nicht anders als 1) und eine
schrittweite (wenn nicht anders als 1) ist.
Das ist die übliche Vorgehensweise und kann extrem viel Tipparbeit sparen.
© https://www.python-lernen.de/funktionen-mit-variabler-parameteranzahl.htm Seite 156
ausgabe(5,3)
Was passiert aber, wenn wir die Anzahl der Parameter nicht kennen? Wenn also eine variable
Parameteranzahl vorliegt? Auch für diesen Fall hat und Python eine Lösung. Wir kennzeichnen
unseren Parameternamen mit einem Stern am Anfang.
Jetzt können wir beliebig viele Parameter übergeben. Die Ausgabe des Beispielcodes ergibt:
Hallo
Welt
guten
Morgen
Jeder einzelne Parameter wird über die print -Ausgabe in einer eigenen Zeile ausgegeben.
Allerdings funktioniert eine Vorbelegung eines einzelnen Parameters nicht mehr, wie wir es
bereits kennengelernt haben:
ausgabe(5,3)
Wir haben bei Funktionen mit variabler Parameteranzahl auch keinen einzelnen Parameter –
die folgende Konstruktion führt zu der Fehlermeldung "SyntaxError: invalid syntax".
Und das gute ist – wir benötigen es in diesem Fall auch nicht wirklich. Wir können beliebig viele
Parameter übergeben. Und dabei meint mit "beliebig viele" auch keinen Inhalt. Folgender Code
wird ohne Fehlermeldung korrekt abgearbeitet – es erfolgt auch keine Ausgabe, denn wir
haben auch keinen Inhalt unserem Parameter "*mehrereParameter" übergeben:
© https://www.python-lernen.de/funktionen-mit-variabler-parameteranzahl.htm Seite 157
ausgabe()
Vorsicht bei der Verwendung! Hier wird eine spätere Fehlersuche aufwendiger – besonders bei
Logikfehlern.
def uebergeben(**kwargs):
for key, value in kwargs.items():
print("{0} = {1}".format(key, value))
uebergeben(vorname="Axel")
vorname = Axel
Und was ist die Herkunft der Bezeichnung **kwargs? Diese kommt aus Englischen
keywordarguments.
In der deutschen Schreibweise müsste dann unser **kwargs dann etwas mit
*mehrereWoerterbuchParameter sich nennen. Kann man machen, muss man aber nicht.
Wie gesagt: Es sind primär die zwei Sternchenoperatoren am Anfang wichtig – alles danach
kann nach Belieben benannt werden.
Mit den herausgegebenen Ergebnissen in Form von Variablen können wir dann im weiteren
Programmcode nach Belieben weiteres anstellen.
def bspfunktionfuerrueckgabe(eingabewert):
rueckgabewert = eingabewert * 2
return rueckgabewert
Wir übergeben in unserem obigen Beispiel die Zahl 5 in unserer Funktion mit dem vielsagenden
Namen „ bspfunktionfuerrueckgabe “. In der Funktion wird nun etwas mit dem
hereingegeben Wert angestellt – im Beispiel einfach verdoppelt und dann über return das
Ergebnis wieder aus der Funktion gegeben.
Außerhalb bekommt unser Funktionsaufruf vorneweg eine Variable, die das zurückgelieferte
Ergebnis aufnehmen soll und ein Gleichheitszeichen.
Die Variable steht außerhalb der Funktion nicht zur Verfügung. Probieren wir in unserem
Python-Programm einfach nach Aufruf der Funktion direkt auf die Variable rueckgabewert ,
die nur innerhalb der Funktion benutzt wird, außerhalb der Funktion zu nutzen, erhalten wir die
Fehlermeldung: „NameError: name 'rueckgabewert' is not defined“
def bspfunktionfuerrueckgabe(eingabewert):
rueckgabewert = eingabewert * 2
return rueckgabewert
Dies ist eine extrem praktische Einrichtung, da wir beim Erstellen unserer Funktion nicht auf die
genutzten Variablennamen außerhalb der Funktion achten müssen. Wir können alles nach
Belieben verwenden.
Bauen wir für das Verständnis ein kleines Python-Programm auf, dass nur für die Nutzung der
Variablen da ist. Dazu haben wir eine Funktion und diese Funktion bekommt Funktionen
© https://www.python-lernen.de/rueckgabewert-funktionen.htm Seite 160
bspfunktion()
print("Variablenwert nach Funktion:", variablenWert)
Ab jetzt sind Fehlermeldungen interessant. Das Programm läuft die ersten 2 Zeilen noch
problemlos. Die Variable mit dem Namen variablenWert wird vor der Funktion gesetzt und
direkt ausgegeben. Das funktioniert problemlos.
Danach wird die Funktion aufgerufen und in der Funktion soll sofort die außerhalb gesetzte
Variable variablenWert ausgegeben werden. Jetzt erhalten wir unsere erste
Fehlermeldung „UnboundLocalError: local variable 'variablenWert' referenced before
assignment“. Die Variable existiert offensichtlich nicht innerhalb der Funktion.
Also nehmen wir diese Zeile raus und setzen der Wert der Variable neu innerhalb der Funktion.
bspfunktion()
print("Variablenwert nach Funktion:", variablenWert)
Nun bekommen wir keine Fehlermeldung mehr aber der gleiche Variablennamen ist
offensichtlich unterschiedlich vom Wert – je nachdem, ob er in oder außerhalb der Funktion
benutzt wird.
Globale Variablen
Nun steigern wir die Komplexität, da wir eine Variable auch als global definieren können.
Innerhalb der Funktion setzen wir unsere Variable " variablenWert " auf global
© https://www.python-lernen.de/rueckgabewert-funktionen.htm Seite 161
bspfunktion()
print("Variablenwert nach Funktion:", variablenWert)
Wir haben also den Wert der außerhalb gesetzten Variablen überschrieben mit einer Variablen
in der Funktion.
Das ist etwas, was man bei Bedarf einfach nochmals durchlesen sollte. Hier der
Vollständigkeit halber.
def fkt_local():
variable = "Inhalt innerhalb local"
def fkt_nonlocal():
nonlocal variable
variable = "Inhalt innerhalb nonlocal"
def fkt_global():
global varibale
variable = "Inhalt innerhalb global"
Schaut man sich das Ergebnis an, wird der Geltungsbereich der Variablen und die
Möglichkeiten, diese durch nonlocal und global zu erweitern, deutlich.
Wie wir universelle verwendbare Funktionen einfach einbindet, sehen wir im folgenden Kapitel.
© https://www.python-lernen.de/rueckgabewert-funktionen.htm Seite 163
© https://www.python-lernen.de/built-in-functions.htm Seite 164
Über dir haben wir eine mächtige Funktion, die uns eine Liste der Attribute und Methoden
von jedem Objekt zurückliefert.
bei Klassen-Objekten wird eine Liste von Namen aller validen Attribute (und auch Basis-
Attribute) zurück übergeben
bei Modulen (Library-Objekten) wird eine Liste der Namen von allen Attributen, die in dem
Modul vorhanden sind.
wenn kein Parameter angegeben wird, wird eine Liste von Namen des aktuellen lokalen
Geltungsbereichs/Namensbereich („local scope“) zurückgeliefert
>>> dir()
Mehr Informationen (Anmerkung: In Python 2.7 wurde noch bedeutend weniger bzw. anders
ausgegeben) erhalten wir über die bereits enthaltenen Funktionen und Typen von Python mit
dir(__builtins__)
>>> dir(__builtins__)
Mehr über die einzelnen Objekte zu erfahren nutzt man die Anweisung help
Möchte man also mehr über die print-Funktion erfahren, gibt man einfach ein:
help(print)
>>> help(print)
print(...)
Die erste Linie zeigt einem, aus welchem Modul diese Funktion ist – im Fall von print
kommt diese Funktion aus bereits im System integrierten Bereich. Wir müssen also nichts in
unser Python-Programm importieren, um diese Funktion nutzen zu können.
Man sieht bei dieser Funktion, dass weitere Parameter übergeben werden können (was auch
Sinn ergibt, sonst wird nichts ausgegeben). Auch sind bereits Parameter mit
Standardausgaben belegt wie beispielsweise der Separator sep=' ' als Leerzeichen.
Hier können wir eingreifen, wenn gewünscht. Anstelle des Leerzeichens des Separators lassen
wir einen Unterstrich ausgeben:
Hallo_Welt_Wie
>>> help(hex)
hex(number, /)
>>> hex(12648430)
'0xc0ffee'
Wir haben wieder eine Funktion die „ab Werk“ sofort in Python zur Verfügung steht.
>>> hex(255)
'0xff'
Wir sehen, dass wir als Rückgabe einen String erhalten – daher wird der Rückgabewert in
Anführungszeichen ausgegeben.
Wofür steht das „0x“? Das ist sehr einfach: das x steht für „heXadezimal“. Hätten wir einen
binären Wert (z.B. 0110011) würde als Präfix „0b“ für „Binär“ ausgegeben. Für eine klare
Abgrenzung zu einer dezimalen Zahl fangen hexadezimale und binäre Zahlen immer damit an
– das wurde bereits in der ANSI Norm für C Compiler anno dazumal festgelegt.
Durch die Schreibweise wird auch direkt im Python-Interpreter eine binäre bzw. Hexadezimale
Eingabe in dezimaler Ausgabe zurückgegeben:
>>> 0xff
255
© https://www.python-lernen.de/built-in-functions.htm Seite 167
>>> help('modules')
>>> help('modules')
Enter any module name to get more help. Or, type "modules spam" to search
Um ein Modul nutzen zu können, müssen wir dieses im ersten Schritt importieren:
© https://www.python-lernen.de/built-in-functions.htm Seite 169
import math
Zur Kontrolle, ob der Import geklappt hat und uns dieses Modul zur Verfügung steht, können
wir die Funktion dir() aufrufen.
dir()
>>> dir()
Um die nun durch „math“ möglichen Funktionen anzusehen, einfach auf diese dir(math)
anwenden.
>>> dir(math)
Es werden bei dem Aufruf keine Anführungszeichen verwendet! Wir wollen das Modul nutzen
und nicht einen Zeichenkette (string).
Um nun weitere Hilfen über help für die im Modul math vorhandenen Möglichkeiten zu
bekommen muss immer das Modul mit angegeben werden. Ansonsten bekommen wir eine
„Traceback“-Fehlermeldung.
>>> help(math.sin)
Help on built-in function sin in module math:
sin(x, /)
Return the sine of x (measured in radians).
>>> sin(45)
Traceback (most recent call last):
File "<pyshell#33>", line 1, in <module>
sin(45)
NameError: name 'sin' is not defined
Wir müssen also immer den Pfad zur Funktion „math“ angeben, um die Funktion nutzen zu
können.
>>> math.sin(45)
0.8509035245341184
© https://www.python-lernen.de/built-in-functions.htm Seite 170
© https://www.python-lernen.de/module-in-python.htm Seite 171
Wir könnten durch „Copy-and-paste“ diese einfach immer wieder in neue Projekte einfügen.
Dagegen sprechen mehrere Dinge. Unser Code wird unnötig aufgebläht, da wir in jeder
Programmdatei (und ein Programm kann ja aus mehreren Dateien durchaus bestehen) den
Code integrieren müssten und Fehler sich so fleißig „vermehren“ und die Beseitigung
dementsprechend aufwendig wird. Das beste Argument ist, dass es eine sehr viel einfachere
Vorgehensweise gibt.
Jetzt wäre es doch sehr praktisch alle unsere Funktionen in einer Datei zu haben, dir wir immer
wieder in unseren Projekten verwenden. Das geht in Python sehr einfach. Man spricht in
Python von Modulen. Schauen wir uns die Verwendung von Modulen an, dann sind die Vorteile
schnell griffig und verständlich.
Dazu gibt es den import -Befehl. Wichtig dabei ist, dass beide Dateien im selben Verzeichnis
sich befinden. Erstellen wir als Erstes unsere Funktionssammlung in der Datei
„fktsammlung.py“. In unserer Sammlung von Funktionen haben wir 2 Beispielfunktionen, von
denen wir annehmen, dass wir diese immer wieder und in verschiedenen Projekten benötigen.
Als Erstes die Funktion, die wir im letzten Kapitel als Beispiel für Rückgabewerte erstellt haben
und eine Funktion zur Begrüßung.
def bspfunktionfuerrueckgabe(eingabewert):
rueckgabewert = eingabewert * 2
return rueckgabewert
Und unsere Funktion zur Begrüßung (da gibt es ein Kartenspiel, das diese Begrüßung
verwendet).
def bspfunktionfuerrueckgabe(eingabewert):
rueckgabewert = eingabewert * 2
return rueckgabewert
def hallomeister():
print("Hallo Herr und Meister")
Diese beiden Funktionen speichern wir in der Datei „fktsammlung.py“. Würden wir das Python-
Programm ablaufen lassen, würde absolut nichts passieren, da zwar die Funktionen definiert
sind, diese aber nicht aufgerufen werden. Dies wollen wir ja aus einer anderen Programmdatei
machen.
Unsere Datei, die unsere Funktionssammlung verwendet, muss sich im selben Verzeichnis wie
unsere Datei „fktsammlung.py“ befinden.
import fktsammlung
Jetzt könnte man natürlich auf die Idee kommen, einfach in unseren neuen Dateien die
Funktion hallomeister aufrufen. Das würde eine Fehlermeldung ergeben. Wir müssen
auch das Modul angeben!
© https://www.python-lernen.de/module-in-python.htm Seite 172
import fktsammlung
fktsammlung.hallomeister()
Die Verwendung von Übergabe- und Rückgabewerten erfolgt wie gewohnt. Nur der Verweis auf
das Modul mit der Punktverknüpfung bleibt. So ist auch immer klar, woher eine Funktion
stammt, falls man doch noch Änderungen oder Erweiterungen in seiner universellen
Funktionssammlung benötigt.
import fktsammlung
fktsammlung.hallomeister()
ergebnisausfunktion = fktsammlung.bspfunktionfuerrueckgabe(2)
print(ergebnisausfunktion)
Modul importieren
Hierbei kann man selbst „sparsam“ importieren, also wirklich nur die Teile eines Moduls, die
man auch für sein Programm benötigt oder alles.
import MODUL
# bei der Nutzung müssen die Namen des Moduls angegeben werden
# Beispiel MODUL.MODULNAME
Im Folgenden werden in diesem Tutorial genutzte Module beschrieben und sind hoffentlich
irgendwann hier komplett zum Nachlesen verfügbar. Ansonsten gibt es die englische
Nachschlageoption unter https://docs.python.org/3/library/
modulname.Klassenname
modulname.variablenname
modulname.funktionsname()
Als konkretes Beispiel: wir nutzen aus dem Modul datetime nur den Bereich date . Dieses
bietet uns eine Funktion für das aktuelle Datum. Wir lassen uns also das Tagesdatum
ausgeben.
import os
import os
print(os.name)
import os
print(os.getcwd())
import os
print(os.environ)
Führt man das Python-Programm mit dem Mac aus, erhält man folgende Ausgabe:
© https://www.python-lernen.de/python-modul-os.htm Seite 176
Wen jetzt die Frage plagt, was man mit den gesetzten Systemvariablen machen könnte, wird
sich den folgenden Befehl freuen:
import os
print(os.name)
print(os.getcwd())
print(os.getenv('HOME'))
posix
/Users/axelp/Documents/Projekte/Python-lernen.de/Skripte
/Users/axelp
import os
print(os.getcwd())
print(os.listdir())
import os
print(os.path.isfile('datei.pdf'))
print(os.path.isdir('datei.pdf'))
Schauen wir uns die Anweisung für den Mac an und aktivieren die Sprachausgabe beim Mac
(die Standardmäßig installiert ist):
import os
os.system('say "Hallo Python"')
Lautsprecher aufdrehen und der Computer sollte nun laut und deutlich „Hallo Python“ von sich
geben.
© https://www.python-lernen.de/python-modul-datetime.htm Seite 178
import datetime
print(dir(datetime))
date
datetime
time
timedelta
timezone
tzinfo
Hier eine kurze Beschreibung. Anhand der folgenden Beispiele werden die
Einsatzmöglichkeiten schnell klar.
Klasse Beschreibung
date Datumsklasse mit Jahr (year), Monat (month) und Tag (day). Voraussetzungen sind der gregorianische
Kalender (und dass dieser gilt)
time idealisierte Zeit mit den Attributen Stunde (hour), Minute (minute), Sekunde (second) und Mikrosekunde
(microsecond). Voraussetzung ist, dass jeder Tag aus exakt 24 * 60 * 60 Sekunden besteht. Idealisiert
deshalb, weil es keine Schaltsekunde gibt.
datetime Kombination aus date und time. Attribute und Voraussetzung entsprechenden den einzelnen Klassen.
timezone Zeitzonen und UTC. Die abstrakte Basisklasse tzinfo wird von timezone genutzt
Importieren wir datetime über from datetime import * erhalten wir alle verfügbaren
Klassennamen:
Man sieht auch sehr schön, wenn wir nur einen Teil (vorzugsweise diesen Teil, den wir auch
benötigen) importieren. Somit spart man Speicherplatz und bekommt ein schnelleres
Pythonprogramm. Der Import nur von date .
Als Ergebnis erhält man das aktuelle Datum – als Beispiel erhält die Variable „2020-01-14“
2020-12-24
Soll es anders ausgegeben werden, können wir dies nach Belieben einstellen:
24.12.2020
Um neben Datum auch die Uhrzeit nutzen zu können, importieren wir alles:
© https://www.python-lernen.de/python-modul-datetime.htm Seite 181
import datetime
weihnachten2020 = datetime.datetime(2020, 12, 4, 15, 30)
print(weihnachten2020.strftime("%H:%M:%S %d.%m.%Y"))
%c Komplette Ausgabe von Datum und Uhrzeit Tue Aug 16 21:30:00 1988 (en_US); Di 16 Aug
21:30:00 1988 (de_DE)
möchte man lieber, dass der Wochentag mit 1 für Montag startet, hilft .timetuple()
Und nun den Wochentag anhand einer Liste als Text ausgeben:
(2020, 1, 22)
© https://www.python-lernen.de/python-modul-datetime.htm Seite 183
Unser Beispiel von oben würde für den Weihnachtstag 2021 folgende Information (in
englischer Schreibweise) ausspucken:
Python-Code:
Ergebnis:
Wir wollen aber die deutsche Schreibweise für Wochentage und Monatsnamen. Dazu
importieren wir am Anfang import locale und nutzen über die Anweisung
locale.setlocale() das Länderkürzel de:
Und nun haben wie überall bei jeder Datumsausgabe die korrekte deutsche Schreibweise:
Möchte man etwas in einem bestehenden Datum austauschen, kann das sehr einfach über
replace() geschehen. Dabei ist der Aufbau:
Nehmen wir an, wir möchten von Weihnachten (wahlweise geht auch der eigene Geburtstag)
dieses und nächsten Jahres den Wochentag und die Kalenderwoche erfahren. Also setzen wir
das Datum von diesem Jahr und tauschen für die zweite Ausgabe das Jahr aus.
(2020, 52, 4)
(2021, 51, 5)
2020 ist Weihnachten in der Kalenderwoche 52 an einem Donnerstag (4) und 2021 an einem
Freitag (5).
Wie gehabt, muss man bei gewünschter Verwendung das Modul importieren und über dir
erhalten wir einen Überblick über die Möglichkeiten:
import time
print(dir(time))
Lassen wir unser Programm für n-Sekunden schlafen gehen. Dann ausgeschlafen erfolgt die
zweite Rückmeldung:
import time
print("Ich bin müde und gehe schlafen")
time.sleep(5)
print("habe geschlafen")
Die Angabe bei time.sleep(n) sind Sekunden. Sollen Millisekunden mitgegeben werden,
dann einfach über die Nachkommastelle!
Wir können auch eine Auswertung der Dauer der Programmausführung machen:
import time
print(time.time())
zeitanfang = time.time()
print("Ich bin müde und gehe schlafen")
time.sleep(5)
print("habe geschlafen")
zeitende = time.time()
print("Dauer Programmausführung:",)
print(zeitende-zeitanfang)
Bei der ersten Ausgabe der Zeit über time.time() erhalten wir eine große Zahl wie z.B.
„1579782074.592673“. Diese Zahl stellt die vergangenen Sekunden seit dem 1.1.1970 dar.
Damit kann man gut rechnen, wenn man eine Anfangszeit von der Endzeit abzieht, wir im
Programm geschehen.
Die Ausgabe:
© https://www.python-lernen.de/python-modul-time.htm Seite 186
1579782074.592673
habe geschlafen
Dauer Programmausführung:
5.000827789306641
Wir sehen, dass unser Programm länger als die 5 Sekunden Schlafenszeit benötigt. Jeder
Befehl und jede Ausgabe frisst Zeit, auch wenn es nur Millisekunden sind. Daher die
„Nachkommazeit“ im Beispiel von ".000827789306641".
import time
print(time.time())
print(time.localasctime())
1579790660.517235
In die gleiche Richtung geht gmtime() - „gm“ steht für „greenwich meantime“, also die
mittlere Sonnenzeit in Greenwich. Und wer sich schon immer mal gefragt hat, warum zur Hölle
Greenwich? Greenwich liegt im Südosten von London und dort war früher das Zentrum der
britischen Marine und es gibt dort eine Sternwarte.
import time
print(time.gmtime())
Und von dieser Zeit-Instanz (mal wieder ein Objekt ;)) können wir nun die Einzelteile verwenden.
Im Index 0 steckt das Jahr – im Index 6 der Wochentag (gezählt wird ab Montag mit 0 – also
bedeutet der Rückgabewert 3, dass es Donnerstag ist)
© https://www.python-lernen.de/python-modul-time.htm Seite 187
import time
jetzt = time.gmtime()
print (jetzt[0]). # ergibt das Jahr
print (jetzt[6]) # Wochentag, Montag ist 0, Di = 1 usw.
2020
import time
jetzt = time.localtime()
print(jetzt)
© https://www.python-lernen.de/python-modul-calendar.htm Seite 188
Januar 2020
Mo Di Mi Do Fr Sa So
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
TextCalendar
LocaleTextCalendar
HTMLCalendar
LocaleHTMLCalendar
TextCalendar gibt das gewählte Kalenderblatt als reinen Text aus, dagegen werden beim
HTMLCalendar auch entsprechende HTML-Tags um die verschiedenen Daten ausgeben.
Sobald der Kalender mit "Locale…" startet, erhält man als Beschriftung die lokale Sprache (in
unserem Fall dann deutsche Monatsbezeichnungen und die abgekürzten Wochentage in
Deutsch).
Über die Anweisung formatmonth wird das gewünschte Jahr und der gewünschte Monat
angegeben.
import calendar
kalenderblatt = calendar.TextCalendar(calendar.MONDAY)
ausgabe = kalenderblatt.formatmonth(2020,1)
print(ausgabe)
oder in Deutsch
import calendar
kalenderblatt = calendar.LocaleTextCalendar(calendar.MONDAY)
ausgabe = kalenderblatt.formatmonth(2020,1)
print(ausgabe)
Januar 2020
Mo Di Mi Do Fr Sa So
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
ein HTML-Kalender:
Möchte man direkt HTML-Code mit Klassen (für das Design später über CSS) erhalten, kann
man die HTML-Variante über LocaleHTMLCalendar auswählen.
import calendar
kalenderblatt = calendar.HTMLCalendar(calendar.MONDAY)
ausgabe = kalenderblatt.formatmonth(2020,1)
print(ausgabe)
Kompletter Jahreskalender
© https://www.python-lernen.de/python-modul-calendar.htm Seite 189
import calendar
kalenderblatt = calendar.LocaleTextCalendar(calendar.MONDAY)
ausgabe = kalenderblatt.formatyear(2020, 2, 1, 1, 3)
print(ausgabe)
2020
Da es sich bei Tkinter um das erste in Python integrierte GUI-Toolkit handelte, ist es in der
Standardinstallation (bei Windows und Mac Os) bereits verfügbar. Die Benennung des Moduls
kommt aus einer Geschichte. „Tk“ steht für „Toolkit“ und „inter“ für Interface und wurde als
erstes für die Sprache „Tcl“ entwickelt.
Tkinter zeichnet sich dadurch aus, dass man nun sehr einfach eine Grafische
Benutzeroberfläche umsetzen kann mit allen üblichen Steuerelementen:
Textlabels
Textboxen
Inputboxen
Schaltflächen (Buttons)
Radiobuttons
Checkbottons
Menüs
Tkinter verfügt über verschiedene Layout-Manager um das Platzieren der einzelnen Elemente
schnell erledigen zu können.
Schauen wir uns im Folgenden an, wie wir Tkinter integrieren, Elemente erstellen, die Platzieren
und die Interaktion zwischen User und Python-Programm ermöglichen.
© https://www.python-lernen.de/tkinter-import.htm Seite 191
import tkinter as tk
Teilweise sieht man auch den Import über from tkinter import * . Das spart zwar im
folgenden Code Tipparbeit, birgt aber die Gefahr von Namenskonflikten, wenn man weitere
Module importiert, die gleiche Namen nutzen. Daher lieber Sicherheit und Stressfrei als ein
bisschen Tipparbeit zu sparen. Zusätzlich sieht man im Tutorial so sehr schnell, dass es sich
um ein Element der Bibliothek tkinter handelt. Wir werden die Elemente dann immer über
tk.__ ansprechen.
import tkinter as tk
Nach dem Import müssen wir unser Fenster initialisieren. Dazu wird ein Konstruktor
aufgerufen, der in die Variable root den Bildschirm setzt:
import tkinter as tk
root = tk.Tk()
Jetzt benötigen wir noch unsere Hauptschleife, damit unsere GUI nicht gleich wieder
verschwindet.
import tkinter as tk
root = tk.Tk()
root.mainloop()
Als Ergebnis erhalten wir mit dem Aufruf des Programms ein neues Fenster –
Betriebssystemtypisch mit den entsprechenden Schließen- und Maximieren-Buttons im
Fensterkopf.
Ein leeres Fenster ist natürlich mäßig spannend. Dieses können wir nun mit den gewünschten
Steuerelementen füllen. Im folgenden Kapitel ein Überblick über die verfügbaren
Steuerelemente (auch Widgets) genannt und dann Schritt für Schritt die Verwendung aller
einzelnen Elemente mit Beispielen und im Einsatz.
© https://www.python-lernen.de/tkinter-steuerelemente.htm Seite 192
Widget Funktion
Menu Kontextmenü
Radiobutton Auswahlfeld, im Gegensatz zu Checkbutton kann nur eine innerhalb einer Gruppe gewählt sein
Scrollbar Scrollleiste
Spinbox Zahlenwertauswahlfeld
Widget-Basisklasse Basisklasse eines Steuerelements (alle Grundfunktionen, die für alle Widgets verfügbar ist)
© https://www.python-lernen.de/tkinter-label-widget.htm Seite 193
Unser bisheriges Programm ergänzen wir vor der Hauptschleife mit dem Label (auch Label-
Widget genannt) mit dem Namen „label1“. Und aus Tradition lassen wir „Hallo Welt“ ausgeben.
import tkinter as tk
root = tk.Tk()
# Textausgabe erzeugen
label1 = tk.Label(root, text="Hallo Welt")
root.mainloop()
Noch passiert gar nichts! Es erfolgt keine Ausgabe. Die Ausgabe müssen wir über die
Anweisung .pack() anstoßen.
import tkinter as tk
root = tk.Tk()
# Textausgabe erzeugen
label1 = tk.Label(root, text="Hallo Welt")
root.mainloop()
Später lernen wir eine weitere Form der Ausgabe anstelle von .pack() kennen. Dadurch wird
Design von der GUI deutlich einfacher.
Den Pfad des Bildes speichern wir unter bild1 , welches über das label2 integriert wird.
Dabei wird das Label ergänzt mit der pack() -Methode, der die Ausrichtung rechts bzw. links
mitgegeben werden kann:
© https://www.python-lernen.de/tkinter-label-widget.htm Seite 194
import tkinter as tk
root = tk.Tk()
# Textausgabe erzeugen
label1 = tk.Label(root, text="Hallo Welt")
# Grafik einbetten
bild1 = tk.PhotoImage(file="biene.png")
label2 = tk.Label(root, image=bild1).pack(side="right")
root.mainloop()
Bitte einmal probieren, erst das Bild auszugeben und dann den Text (der dann ohne die
Ausrichtung links angegeben wird). Als Ergebnis erhalten wir:
Für die Ausrichtung über das Attribut side= stehen uns 3 Werte zur Verfügung:
import tkinter as tk
root = tk.Tk()
# Textausgabe erzeugen
label1 = tk.Label(root, text="Hallo Welt")
root.mainloop()
Vordergrundfarbe fg
Jetzt kommt das Attribut fg= für die Vordergrundfarbe hinzu. Die Farbangabe geschieht über
die englischen Farbnamen bzw. über die Hexadezimalangaben für Farben (wie man es von
HTML kennt über #ff00ff ).
# Textausgabe erzeugen
label1 = tk.Label(root, text="Hallo Welt", fg="red")
Zur besseren Lesbarkeit wird folgenden die Attribute auf mehrere Zeilen verteilt.
Hintergrundfarbe bg
Dasselbe wie bei der Vordergrundfarbe können wir über das Attribut bg= für eine
Hintergrundfarbe (backgroundcolor) umsetzen. Die Trennung zwischen den einzelnen
Attributen erfolgt über jeweils ein Komma:
# Textausgabe erzeugen
label1 = tk.Label(root, text='Hallo Welt',
fg='#00ff00',
bg='orange')
© https://www.python-lernen.de/tkinter-schriftart-schriftgroesse.htm Seite 196
# Textausgabe erzeugen
label1 = tk.Label(root, text='Hallo Welt',
fg='#00ff00',
bg='orange',
font=('times', 25, 'bold', 'italic'))
© https://www.python-lernen.de/tkinter-gui-platzierung-grid.htm Seite 197
import tkinter as tk
root = tk.Tk()
root.mainloop()
Wir sehen hier sehr schön, wie die einzelnen Texte in die entsprechenden Reihen und Spalten
platziert werden. Dabei bestimmt der benötigte Platz des Textes die Spaltenbreite.
Haben wir eine weitere Ausgabe in Spalte 0 und Zeile 3, die weniger Platz benötigt, wird diese
standardmäßig mittig ausgerichtet:
Über die Anweisung print(dir(tk.Grid)) erhalten wir alle Informationen über die
Möglichkeiten von Grid .
Über das Attribut sticky= können wir unseren Inhalt an einer Seite ausrichten und sind nicht
auf die zentrierte Ausgabe festgelegt. Als Attributwert diesen die Himmelsrichtungen wir „n, s,
w, e, sw, se, ..“
import tkinter as tk
root = tk.Tk()
root.mainloop()
Unser gelber Inhalt (R2/C0) ist jetzt rechts ausgerichtet – sprich im Osten (englisch east = „e“)
eingabefeld_wert=tk.StringVar()
eingabefeld=tk.Entry(root, textvariable=eingabefeld_wert)
eingabefeld.pack()
Über das Attribut textvariable= wird eine Steuerelementvariable gesetzt, über die wir auf
den Inhalt (sprich die Nutzereingabe) lesend zugreifen können über variablenname.get() .
Genauso können wir auch selber Inhalt aus dem Programm in diesen Bereich schreiben über
variablenname.set() .
eingabefeld_wert=tk.StringVar()
eingabefeld=tk.Entry(root, textvariable=eingabefeld_wert)
eingabefeld.pack()
eingabefeld_wert.set('12345')
Daher soll doch bitte anstelle von der eigentlichen Eingabe dann die typischen Sterne kommen.
Kein Problem bei Tkinter: wir haben einen weiteren Parameter, der die Zeichen festlegt, die
anstelle einer Eingabe angezeigt werden. Dieser Paramater ist show="*" und sollte mehr als
ein Zeichen im Parameter eingetragen werden, wird nur das erste Zeichen verwendet. Einfach
einmal testen über show=":)"
eingabefeld_wert=tk.StringVar()
eingabefeld=tk.Entry(root, textvariable=eingabefeld_wert, show="*")
eingabefeld.pack()
Der Parameter kann auch in anderer Form übergeben werden. Dadurch wird der Code
übersichtlicher:
eingabefeld=tk.Entry(root)
eingabefeld_wert=tk.StringVar()
eingabefeld["textvariable"] = eingabefeld_wert
eingabefeld["show"] = "*"
eingabefeld.pack()
import tkinter as tk
root = tk.Tk()
# Textausgabe erzeugen
label1 = tk.Label(root, text="Hallo Welt")
label1.pack()
root.mainloop()
Das erzeugt uns eine Schaltfläche, die zwar noch nichts tut, aber schon einmal angezeigt wird.
Die Schreibweise über 2 Zeilen mit pack() können wir noch kürzer machen, indem wir das Pack
an unsere Anweisung tk.Button().pack() „anheften“ (diese Schreibweise klappt bei allen
Elementen, so auch bei dem Label für die Textausgabe). Das macht unseren Code schlanker
(was zum Lernen suboptimal ist, aber man mal gesehen haben sollte):
import tkinter as tk
root = tk.Tk()
label1 = tk.Label(root, text="Hallo Welt").pack()
schaltf1 = tk.Button(root, text="Aktion durchführen").pack()
root.mainloop()
Auch die Platzierung der Schaltfläche können wir wie beim Label-Widget über
side="left|center|right") beeinflussen.
Zusätzlich benötigen wir noch eine Funktion, die etwas macht. Hier nutzen wir die „Beenden“-
Funktion von Tkinter .destroy .
Mit anklicken der Schaltfläche wird also unser Tkinter-Fenster geschlossen. Hier der komplette
Code:
© https://www.python-lernen.de/tkinter-button.htm Seite 201
import tkinter as tk
root = tk.Tk()
root.mainloop()
Im nächsten Schritt wollen wir eigene Aktionen mit der Schaltfläche „verbinden“.
import tkinter as tk
def aktionSF():
label3 = tk.Label(root, text="Aktion durchgeführt", bg="yellow")
label3.pack()
root = tk.Tk()
root.mainloop()
Jedes Mal, wenn wir nun die Schaltfläche anklicken erweitert sich das Fenster mit der Ausgabe
„Aktion durchgeführt“.
Um diese in Tkinter nutzen zu können, müssen die Benennung von Tkinter genutzt werden.
tkinter.StringVar str
tkinter.IntVar int
tkinter.DoubleVar float
tkinter.BooleanVar bool
© https://www.python-lernen.de/tkinter-button.htm Seite 202
Wir wollen in unserem kleinen Programm ein Feld mit einer Zahl auslesen und die Gradangabe
in Kelvin umrechnen. Mathematisch schön einfach, da wir einfach zu Gradangabe einfach 273
dazurechnen. Dazu müssen wir für unser Feld Entry die Art der Textvariable mitgeben – in
folgendem Beispiel ein String über tkinter.StringVar
eingabefeld_wert=tk.StringVar()
eingabefeld=tk.Entry(root, textvariable=eingabefeld_wert)
eingabefeld.pack()
Auf den vom Benutzer eingegebenen Inhalt wollen wir nun zugreifen, wenn der Button
angeklickt wird:
In der Funktion lassen wir zu Kontrolle einfach den Wert ausgeben. Unser erster Test dazu:
def grad_nach_kelvin():
print(eingabefeld_wert)
PY_VAR0
Was müssen wir machen, um auf den eigentlichen Inhalt zuzugreifen? Wir müssen diese mit
get() auslesen! Nun erhalten wir auch den eingegebenen Inhalt. Aber warum nutzen wir hier
Strings und nicht einen numerischen Datentyp? Probieren wir einfach einmal aus, was passiert,
wenn wir tk.IntVar() anstelle von tk.StringVar() nutzen.
Solange der Nutzer Ganzzahlen eingibt, ist alles gut. Sobald er versehentlich Text eingibt und
der Button geklickt wird, wird Python einen Fehler.
Es ist also gerade einfacher für uns, alle Eingaben zuzulassen und dann die Eingabe zu
„casten“ (siehe entsprechendes Kapitel):
Jetzt fehlt uns noch die Umrechnung von Grad Celsius in Kelvin. Hier die Formal dazu:
def grad_nach_kelvin():
# print(eingabefeld_wert.get())
grad = int(eingabefeld_wert.get())
kelvin = grad + 273
textausgabe = tk.Label(root, text=kelvin, bg="yellow")
textausgabe.pack()
Und schon haben wir einen Umrechner, den man garantiert jeden Tag benötigt :)
import tkinter as tk
root = tk.Tk()
def grad_nach_kelvin():
# print(eingabefeld_wert.get())
grad = int(eingabefeld_wert.get())
kelvin = grad + 273
textausgabe = tk.Label(root, text=kelvin, bg="yellow")
textausgabe.pack()
eingabefeld_wert=tk.StringVar()
eingabefeld=tk.Entry(root, textvariable=eingabefeld_wert)
eingabefeld.pack()
root.mainloop()
highlightthickness="20"
highlightbackground="white", highlightcolor="blue"
© https://www.python-lernen.de/tkinter-cursor-aussehen.htm Seite 204
Cursorform ändern
Cursor verändern bei Mauskontakt
Über das Attribut cursor= können wir das Aussehen des Cursors verändern, wenn die Maus
unsere Schaltfläche berührt. Dabei haben wir verschiedene Aussehen zur Auswahl:
cursor='tcross'
cursor='hand1'
cursor='hand2'
cursor='heart'
cursor='pencil'
© https://www.python-lernen.de/tkinter-hoehe-breite-setzen.htm Seite 205
Haben wir nun genügend Platz können wir den Text in diesem Bereich platzieren. Das läuft über
die Himmelsrichtungen und Kombinationen davon. Soll etwas links platziert werden, dann ist
dies die Angabe anchor="w"
Radiobutton in Tkinter
Der Name Radiobutton hat seinen technischen Ursprung von Omas Radio aus der Küche.
Dieses hatte Knöpfe, die man mit einzelnen Radiosendern belegen konnte. Drücke man einen,
sprang der bisher gedrückte in seine Ausgangsstellung. Man. konnte also immer nur einen
Sender gleichzeitig wählen (was auch irgendwie sinnvoll ist).
Das gleiche gilt für unsere Radiobutton in einer GUI. Hier haben wir die tpyschen Elemente, um
Eingaben abzufragen wie beispielsweise Mann oder Frau etc.
Radiobuttons machen also erst Sinn, wenn man mehr als eine Auswahl hat (sonst wäre die
Checkbutton die erste Wahl).
Wir haben bei Radiobuttons eine Beschriftung und einen Rückgabewert jeder Auswahl. Hierbei
kann aber Beschriftung und Rückgabewert gleich sein, muss aber nicht. Sprich wir haben einen
Button mit der Beschriftung „Herr“ und als Rückgabewert wird „m“ geliefert bzw. („Frau“ mit
Rückgabewert „w“). Im ersten Beispiel zum Verständnis des Widgets ist Beschriftung und
Rückgabewert identisch.
Im nächsten Schritt müssen wir festlegen, welche Art unsere Rückgabevariable hat (String, Int,
…) und wie diese benannt ist:
ausgewaehlt = tk.StringVar()
Und nun können wir unsere Liste durchlaufen und die Radiobuttons ausgeben lassen:
Wir erhalten die Lustige Ausgabe mit durchstrichenen Buttons, weil wir keinen Wert vorab
gesetzt haben! Wir können auch einen Wert vorab als erste angewählten Wert setzen:
ausgewaehlt = tk.StringVar()
ausgewaehlt.set("Frau")
print(ausgewaehlt.get())
aktuell_ausgewaehlt = ausgewaehlt.get()
Jetzt wollen wir direkt bei Änderung des Wertes eine Aktion anstoßen. Also wird das typische
command aufgenommen:
def ausgabe():
print(ausgewaehlt.get())
aktuell_ausgewaehlt = ausgewaehlt.get()
textausgabe = tk.Label(root, text=aktuell_ausgewaehlt, bg="orange")
textausgabe.pack()
ausgewaehlt = tk.StringVar()
ausgewaehlt.set("Frau")
Würde man den Rückgabewert anders als den Anzeigewert setzen wollen, würde anstelle der
Liste ein Dictionary nutzen.
Checkbutton/Checkbox
Im Gegensatz zum Radiobutton kann jeder Checkbutton einen eigenständigen Status haben,
wobei es als Status angeklickt und nicht angeklickt, sprich aktiv oder deaktiviert gibt.
checkbox01 = tk.Checkbutton(root)
checkbox01["text"] = "Sport treiben"
checkbox01.pack()
Wollen wir den Wert setzen bzw. anfragen, müssen wir einen Variablennamen an den
Checkbutton „binden“:
checkbox01 = tk.Checkbutton(root)
checkbox01["text"] = "Sport treiben"
checkbox01.pack()
checkbox01var = tk.BooleanVar()
checkbox01["variable"] = checkbox01var
Das Abfragen des Status erfolgt wie bereits bei den anderen Widgets über get() . Als
Rückgabewert erhalten wir „1“ für „angeklickt“ und „0“ für „nicht angeklickt“.
print(checkbox01var.get())
Wollen wir den Status ändern, können wir über set() diesen entsprechend setzen:
checkbox01var.set(True)
import tkinter as tk
root = tk.Tk()
def ausgabe():
print(checkbox01var.get())
aktuell_ausgewaehlt = checkbox01var.get()
textausgabe = tk.Label(root, text=aktuell_ausgewaehlt, bg="orange")
textausgabe.pack()
checkbox01 = tk.Checkbutton(root)
checkbox01["text"] = "Sport treiben"
checkbox01.pack()
checkbox01var = tk.BooleanVar()
checkbox01var.set(True)
checkbox01["variable"] = checkbox01var
checkbox02 = tk.Checkbutton(root)
checkbox02["text"] = "Lesen"
checkbox02.pack()
checkbox02var = tk.BooleanVar()
checkbox02["variable"] = checkbox02var
checkbox03 = tk.Checkbutton(root)
checkbox03["text"] = "Filme schauen"
checkbox03.pack()
checkbox03var = tk.BooleanVar()
checkbox03["variable"] = checkbox03var
root.mainloop()
offvalue
onvalue
Mögliche Attribute:
activebackground, activeforeground, anchor, background, bd, bg, bor- derwidth, command, fg,
foreground, height, justify, overrelief, padx, pady, relief, state, takefocus, text, textvariable, width
© https://www.python-lernen.de/tkinter-labelframe.htm Seite 211
Diese müssen wir dann noch den einzelnen Steuerelementen zuweisen und über pack()
ausgeben lassen. Der komplette Code:
import tkinter as tk
root = tk.Tk()
checkbox01 = tk.Checkbutton(gruppehobby)
checkbox01["text"] = "Sport treiben"
checkbox01.pack()
checkbox01var = tk.BooleanVar()
checkbox01["variable"] = checkbox01var
checkbox02 = tk.Checkbutton(gruppehobby)
checkbox02["text"] = "Lesen"
checkbox02.pack()
checkbox02var = tk.BooleanVar()
checkbox02["variable"] = checkbox02var
checkbox03 = tk.Checkbutton(gruppehobby)
checkbox03["text"] = "Filme schauen"
checkbox03.pack()
checkbox03var = tk.BooleanVar()
checkbox03["variable"] = checkbox03var
root.mainloop()
Wollen wir nun die Elemente noch sauber untereinander, können diese über anchor="w"
ausgerichtet werden:
import tkinter as tk
root = tk.Tk()
checkbox01 = tk.Checkbutton(gruppehobby)
checkbox01["text"] = "Sport treiben"
checkbox01.pack(anchor="w")
checkbox01var = tk.BooleanVar()
checkbox01["variable"] = checkbox01var
checkbox02 = tk.Checkbutton(gruppehobby)
checkbox02["text"] = "Lesen"
checkbox02.pack(anchor="w")
checkbox02var = tk.BooleanVar()
checkbox02["variable"] = checkbox02var
checkbox03 = tk.Checkbutton(gruppehobby)
checkbox03["text"] = "Filme schauen"
checkbox03.pack(anchor="w")
checkbox03var = tk.BooleanVar()
checkbox03["variable"] = checkbox03var
root.mainloop()
Weitere Optionen
labelanchor = n/ne/e/se/s/sw/w/nw
labelwidget
Anstelle von Beschriftung ein anderes Widget (im Bereich wo ansonsten die Beschriftung
sitzen würde)
© https://www.python-lernen.de/tkinter-listbox.htm Seite 213
Im folgenden Beispiel eine Einkaufsliste. Der Inhalt wird als Liste in Python erstellt und dann
über eine for-Schleife jeder einzelner Listenpunkt eingefügt.
import tkinter as tk
fenster = tk.Tk()
lbox = tk.Listbox(fenster)
lbox.pack()
fenster.mainloop()
Standardmäßig kann nur 1 Auswahl gemacht werden, bis etwas anderes eingestellt wird. Wir
erhalten über curselection() den Index des gewählten Listenpunktes:
import tkinter as tk
fenster = tk.Tk()
def ausgabe():
print(lbox.curselection())
aktuell_ausgewaehlt = lbox.curselection()
textausgabe = tk.Label(fenster, text=aktuell_ausgewaehlt, bg="orange")
textausgabe.pack()
lbox = tk.Listbox(fenster)
lbox.pack()
fenster.mainloop()
Wollen wir es ermöglichen, dass mehrere Einträge ausgewählt werden können, geschieht dies
über lbox["selectmode"] = "extended"
© https://www.python-lernen.de/tkinter-listbox.htm Seite 214
Jetzt erhalten wir als Rückgabewert, wenn das zweite, dritte und fünfte Element gewählt wurde
dann (1, 2, 4) (zur Erinnerung: Computer fangen bei 0 an zu zählen).
selectmode:
import webbrowser
Im nächsten Schritt kann bereits eine URL geöffnet werden. Der übersichtlichkeitshalber wird
erst eine Variable mit der URL erstellt und diese dann im Befehl webbrowser.open()
genutzt:
import webbrowser
url = 'https://www.Python-lernen.de/'
webbrowser.open(url)
import webbrowser
url = 'https://www.Python-lernen.de/'
webbrowser.open_new(url)
Und noch ein Befehl: allerdings wieder das gleiche wie oben kann über die Anweisung
webbrowser.open_new_tab(url) erreicht werden.
import webbrowser
url = 'https://www.Python-lernen.de/'
webbrowser.open_new_tab(url)
firefox
safari
chrome
opera
windows-default
Und der Code als komplettes Beispiel, in dem die URL in Browser Firefox geöffnet wird:
import webbrowser
url = 'https://www.Python-lernen.de/'
webbrowser.get('firefox').open(url)
Der Browser ‚windows-default‘ funktioniert nur auf Windows Systemen und erzeugt auf
© https://www.python-lernen.de/webbrowser-mit-python-nutzen.htm Seite 216
anderen Systemen einen „webbrowser.Error“. Das Gleiche gilt für ‚safari‘ – dieser funktioniert
nur auf macOS Plattformen.
Der Parameter „neu“ kann 0 (Standard) für eine vorhandene Browserinstanz sein, 1 für ein
neues Browserfenster (wenn möglich) und 2 für ein neues Browserfenster mit Tab. Testen –
reagiert je nach Betriebssystem anders.
import webbrowser
url = 'https://www.google.de/?q='
Wollen wir die Suche direkt ausgeführt bekommen, dann ändert sich die URL entsprechend:
import webbrowser
url = 'https://www.google.de/search?q='
Im Browser gibt man eine URL an, um eine Website abzurufen. Dabei steht URL für „Uniform
Resource Locator“ – also übersetzt „einheitlicher Ressourcenzeiger“. Dabei kann die URL viele
Informationen enthalten.
Aufbau URL:
Protokoll: Am Anfang steht das Protokoll, z.B. https, http, ftp usw.
Port: manchmal kommt danach ein Doppelpunkt mit einer Nummer danach. Dadurch wird der
Port festgelegt. Standardmäßig steht der Port 80 für http und der Port 443 für https – diese
müssen nicht angegeben werden. Aussehen würde es sonst so: https://www.python-
lernen.de:443/
Pfad: Wenn nicht dir Startseite angezeigt werden soll, wird der Pfad zur gewünschten Seite
mitgegebenen
Query-String: nach dem Fragezeichen können zusätzlich Daten über dir URL übertragen
werden. Im Beispiel wird der Inhalt für die Suchfunktion übertragen
Sprungmarke: Am Ende kann gekennzeichnet durch die Raute noch eine Sprungmarke
innerhalb der Seite mitgegeben werden
Die URLLIB-Bibliothek unterstützt das Erstellen, Herunterladen und Parsing von URLs. Dafür
stehen in der Bibliothek 5 Module zur Verfügung, von denen 4 durch den Programmierer
eingesetzt werden können:
request
error
parse
robotparser
Über error können wir auf Fehler während dem Zugriff etc. reagieren
Und über robotparser können wir den Inhalt der robots.txt auswerten.
import urllib
print(help(urllib))
Über die Help-Funktion sehen wir wieder unsere 5 Module (request, error, parse, …), die wir
nutzen können.
Lassen wir uns mit dir alle Angaben ausgeben, sehen wir die vielen Methoden und Klassen,
die uns über das Modul zur Verfügung stehen:
Wir wollen ein URL laden, daher benötigen wir urlopen(url) . Zum Testen nutzen wir die
Beispielseite www.example.com
Als Rückgabewert erhalten wir ein Response-Objekt (kann man wohl am besten mit Antwort-
Objekt übersetzten) – siehe type(rueckgabewert) .
<class 'http.client.HTTPResponse'>
Hier erhalten wir als Rückgabe den Wert 200 . Dieser sagt uns, dass die Anfrage geklappt hat.
Es gibt verschiedene Rückgabewerte, die über Erfolg oder Misserfolg der Aktion uns alles
sagen. Diese nennen sich http Status Codes:
200: OK
403: Forbidden
Wir können genauso die Größe der „Datei“ über .length abfragen:
Und wir können den Anfang des Inhalts anzeigen lassen über .peek() :
Und hier bekommen wir folgende Rückgabe – wichtig ist der Anfang mit b' !
© https://www.python-lernen.de/bibliothek-urllib.htm Seite 220
b'<!doctype html>
<html>
<head>
<title>Example Domain</title>
<meta charset="utf-8" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type="text/css">
body {
background-color: #f0f0f2;
margin: 0;
padding
Dieses b' am Anfang sagt uns, dass es sich um ein Byte-Objekt handelt.
Jetzt können wir die komplette Datei auslesen über die Anweisung rueckantwort.read() .
Wir bekommen als Rückantwort die Bestätigung über das Überprüfen des Typs, dass es sich
um einen Byte-Strom handelt:
<class 'bytes'>
Den Inhalt können wir umwandeln. Dazu muss das Format bekannt sein. Wir haben bei den
ersten Zeilen des Inhalts gesehen, dass es sich um das UTF8-Format handelt.
Danach liegt und ein String vor („<class 'str'>“) und wir können dieses ausgeben.
<!doctype html>
<html>
<head>
<title>Example Domain</title>
<meta charset="utf-8" />
…
Nachdem wir den Inhalt ausgelesen haben, wird die Verbindung automatisch geschlossen. Es
kann der Inhalt kein zweites Mal aus dem Byte-Strom ausgelesen werden!
Wollen wir jetzt einen Inhalt herunterladen wie z.B. die Website www.example.com, dann klappt
das in einem Dreizeiler:
import requests
r = requests.get('https://www.example.com/')
print(r.text)
<!doctype html>
<html>
<head>
<title>Example Domain</title>
<meta charset="utf-8" />
…
Das klappt sowohl bei http bei wie auch bei https – also kein Problem mit SSL-Zertifikaten.
import requests
r = requests.get('https://www.example.com/')
print (r.status_code)
Wollen wir nur die Information, ob es geklappt hat oder nicht: r.ok
© https://www.python-lernen.de/requests-bibliothek-online-zugriffe.htm Seite 223
Online-Grafikdatei herunterladen
Wollen wir ein Bild von einer Website herunterladen, dann klappt das ebenso einfach. Wir
wollen von unserer Python Kurs das GIF-Bild mit der animierten Biene herunterladen. Dazu
benötigen wir die URL „https://www.python-lernen.de/bilder/biene-sprite-animiert-01.gif“
(rechte Maustaste auf das Bild und „Bild in neuem Tab öffnen“ gibt uns die URL)
Anstelle des Inhalts als r.text bekommen wir diesen als r.content ausgelesen.
import requests
r = requests.get('https://www.python-lernen.de/bilder/biene-sprite-animiert-01.gif')
print(r.content)
Geben wir den Inhalt direkt auf dem Bildschirm aus sehen wir anhand der Anfangszeichen,
dass es sich um eine binäre Datei (b') handelt und um das Grafikformat GIF.
b'GIF89a2�w!�
import requests
r = requests.get('https://www.python-lernen.de/bilder/biene-sprite-animiert-01.gif')
Jetzt befindet sich in unserem Verzeichnis eine Grafikdatei mit dem Namen „biene.gif“. Einfach
mal nachsehen ;)
import requests
r = requests.get('https://www.example.com/')
print (r.status_code)
print (r.ok)
print (r.headers)
Die Bibliothek unterstützt das einfache übermitteln von Parametern sowohl mit „get“ wie auch
„post“. Der Online-Dienst https://httpbin.org/ ermöglicht das einfach Testen der jeweiligen
Anfragen:
import requests
print (r.status_code)
print (r.ok)
{
"args": {},
"data": "",
"files": {},
"form": {
"key1": "value1",
"key2": "value2"
},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Content-Length": "23",
"Content-Type": "application/x-www-form-urlencoded",
"Host": "httpbin.org",
"User-Agent": "python-requests/2.23.0",
"X-Amzn-Trace-Id": "Root=1-5e5a4638-d6b461203ebe5a0becaf4e4c"
},
"json": null,
"origin": "79.197.98.81",
"url": "http://httpbin.org/post"
}
200
True
import requests
payload = {'schluessel1': 'wert1', 'schluessel2': 'wert2'}
r = requests.get("http://httpbin.org/get", params=payload)
print (r.text)
"args": {
"schluessel1": "wert1",
"schluessel2": "wert2"
},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Host": "httpbin.org",
"User-Agent": "python-requests/2.23.0",
"X-Amzn-Trace-Id": "Root=1-5e5a46eb-f349c1c4e9543820b57730d8"
},
"origin": "79.197.98.81",
"url": "http://httpbin.org/get?schluessel1=wert1&schluessel2=wert2"
}
Die Bibliothek erzeugt also die korrekten Parameter und kümmert sich um die korrekte
Übergabe.
Anstelle von einer Textrückgabe können wir auch es Form von JSON erhalten. Dazu einfach
folgende Zeile ändern:
import requests
payload = {'schluessel1': 'wert1', 'schluessel2': 'wert2'}
r = requests.get("http://httpbin.org/get", params=payload)
r_dict = r.json()
print(r_dict['args'])
Rückgabe:
import requests
r = requests.get('http://httpbin.org/basic-auth/a/b', auth=('a', 'b'))
print (r.status_code)
print (r.ok)
print (r.text)
200
True
{
"authenticated": true,
"user": "a"
}
Verzögerungen einplanen
Wenn der Zugriff auf die Online-Ressource länger dauert, kann man diese Verzögerung
„einplanen“.
Website Hersteller
Weitere Informationen (auch in deutscher Übersetzung) findet sich auf der Programmierer-
Websites der Bibliothek requests unter:
https://requests.readthedocs.io/de/latest/index.html
© https://www.python-lernen.de/selenium-fernsteuern-browser.htm Seite 227
Im ersten Schritt müssen wir Selenium installieren. Das passiert über pip :
Jetzt benötigen wir den passenden Treiber (engl. „driver“) für unseren gewählten Browser (und
Betriebssystem) unsere Wahl. Wenn wir Chrome nutzen, dann findet sich der Treiber unter:
https://chromedriver.chromium.org/downloads
Für Firefox:
https://github.com/mozilla/geckodriver/releases
Bei Mac Catalina kommt es zu Problemen wegen der Downloadquelle. Mehr dazu unter
https://firefox-source-docs.mozilla.org/testing/geckodriver/Notarization.html
# für Chrome
xattr -r -d com.apple.quarantine chromedriver
# für Firefox
xattr -r -d com.apple.quarantine geckodriver
© https://www.python-lernen.de/selenium-fernsteuern-browser.htm Seite 228
Jetzt können wir unser erstes Python-Programm mit dem Modul Selenium schreiben:
driver = webdriver.Chrome('/Users/ich/Python-lernen.de/fs/chromedriver')
driver.get('https://www.google.de/')
Als Ausgabe erhalten wir nun den Browser gestartet und Google.de angezeigt:
Chrome über Selenium: Ausgabe Chrome wird von automatisierten Testsoftware gesteuert
Nachdem der Browser gestartet wurde und die Seite aufgebaut wurde, bleibt der Browser
offen.
Jetzt wollen wir Aktionen im Browser ausführen. Allerdings sollten wir kurz warten, dass die
Seite auch aufgerufen wurde und komplett dargestellt ist.
Daher schicken wir den Browser nach dem Aufruf der URL erst einmal schlafen. Dazu wird das
Modul time importiert und dann schicken wir unser Python-Programm 3 Sekunden schlafen
(ein PowerNap soll gesund sein).
driver = webdriver.Chrome('/Users/ich/Python-lernen.de/fs/chromedriver')
driver.get('https://www.google.de/')
time.sleep(3)
Jetzt packen wir das Suchfeld in eine Variable über find_element_by_name() und
schicken dort Tastatureingaben hin:
© https://www.python-lernen.de/selenium-fernsteuern-browser.htm Seite 229
driver = webdriver.Chrome('/Users/ich/Python-lernen.de/fs/chromedriver')
driver.get('https://www.google.de/')
time.sleep(3)
aktion = driver.find_element_by_name('q')
aktion.send_keys("Python lernen")
aktion.submit()
time.sleep(10)
driver.quit()
© https://www.python-lernen.de/bibliothek-matplotlib.htm Seite 230
Zahlreiche Beispiele finden sich auf der dazugehörigen Website unter https://matplotlib.org
Nach der Installation können wir die Bibliothek durch den typischen Import in Python nutzen:
Hier wird die Abkürzung „plt“ genutzt – Konvention hilft anderen Programmieren schneller
Python-Code zu verstehen, daher sollte man solche Konventionen einhalten.
Wir erstellen nun eine Liste mit Zahlen, die wir als Diagramm ausgeben lassen wollen:
daten = [4, 7, 1, 9, 5, 2, 8]
Jetzt müssen wir die Form der Ausgabe festlegen über plot() und die Ausgabe starten über
show() :
daten = [4, 7, 1, 9, 5, 2, 8]
plt.plot(daten)
plt.show()
daten = [4, 7, 1, 9, 5, 2, 8]
plt.plot(daten)
plt.xlabel("X-Werte")
plt.ylabel("Y-Werte")
plt.show()
Als Ergebnis erhalten wir die Beschriftung unter der x-Achse und links neben der y-Achse.
ywerte = [4, 7, 1, 9, 5, 2, 8]
xwerte = [1, 2, 3, 4, 5, 6, 7]
plt.bar(xwerte, ywerte)
plt.xlabel("X-Werte")
plt.ylabel("Y-Werte")
plt.show()
Balkendiagramm
ywerte = [4, 7, 1, 9, 5, 2, 8]
xwerte = [1, 2, 3, 4, 5, 6, 7]
plt.scatter(xwerte, ywerte)
plt.xlabel("X-Werte")
plt.ylabel("Y-Werte")
plt.show()
ywerte = [4, 7, 1, 9, 5, 2, 8]
xwerte = [1, 2, 3, 4, 5, 6, 7]
plt.plot(xwerte, ywerte)
plt.scatter(xwerte, ywerte)
plt.xlabel("X-Werte")
plt.ylabel("Y-Werte")
plt.show()
Möchte man nun die Punkte hervorheben und diesen eine andere Farbe zuweisen, ist das kein
Problem. Die Anweisung plt.scatter(x,y,c=color) wird um den Parameter „c“ für
Farbe (color) erweitert:
plt.savefig('gespeichertesdiagramm.png')
Diese kann anstelle von plt.show() oder zusätzlich zu der Bildschirmausgabe erfolgen.
ywerte = [4, 7, 1, 9, 5, 2, 8]
xwerte = [1, 2, 3, 4, 5, 6, 7]
plt.plot(xwerte, ywerte)
plt.scatter(xwerte, ywerte, color='red')
plt.xlabel("X-Werte")
plt.ylabel("Y-Werte")
x1 = 1
x2 = 7
y1 = 3.5
y2 = 4.5
plt.plot((x1, x2), (y1, y2))
plt.show()
© https://www.python-lernen.de/bibliothek-matplotlib.htm Seite 235
Und somit haben wir automatisch ein drittes Element mit einer automatisch zugewiesenen
Farbe:
Trendlinie in Diagramm
Hier soll die einfache Anwendung in Form von der Auswertung von Worthäufigkeiten gezeigt
werden und die Ausgabe einer Grafik über die Wörterhäufigkeitsverteilung. Das schöne ist, wie
einfach dies über die NLTK-Bibliothek möglich ist.
Im ersten Schritt muss in Python die NLTK-Bibliothek über PIP installiert werden:
Jetzt können wir die Bibliothek auf Text loslassen. Als Erstes müssen wir diese aktivieren
durch import nltk und dann benötigen wir einen Text. Wir nutzen die bekannte Ballade
„Erlkönig“ von „Wolfgang von Goethe“. Den kompletten Text gibt es bei Wikipedia unter:
https://de.wikipedia.org/wiki/Erlk%C3%B6nig_(Ballade)
import nltk
woerter = inhalt.split()
worthaeufigkeit = nltk.FreqDist(woerter)
print(worthaeufigkeit)
print(worthaeufigkeit.most_common())
Unseren Text in der Variable inhalt wandeln wir über die Funktion split() in eine Liste
mit dem Namen woerter um, die wir mit Methoden unserer Bibliothek nltk nutzen können.
Über die Methode most_common() erhalten wir die Verteilung - als Ergebnis bekommen wir
angezeigt:
python3 worthaeufigkeit-erlkoenig.py
[('Erlkönig', 3), ('mit', 3), ('so', 2), ('und', 2), ('ist', 2), ('den', 2), ('er', 2), ('ihn', 2), ('Mein', 2), ('Sohn,',
2), ('du', 2), ('-', 2), ('Der', 1), ('Wer', 1), ('reitet', 1), ('spät', 1), ('durch', 1), ('Nacht', 1), ('Wind?', 1),
('Es', 1), ('der', 1), ('Vater', 1), ('seinem', 1), ('Kind;', 1), ('Er', 1), ('hat', 1), ('Knaben', 1), ('wohl', 1),
('in', 1), ('dem', 1), ('Arm,', 1), ('faßt', 1), ('sicher,', 1), ('hält', 1), ('warm.', 1), ('was', 1), ('birgst', 1),
('bang', 1), ('dein', 1), ('Gesicht?', 1), ('Siehst,', 1), ('Vater,', 1), ('nicht?', 1), ('Den', 1), ('Kron', 1),
('Schweif?', 1), ('es', 1), ('ein', 1), ('Nebelstreif.', 1), ('"Du', 1), ('liebes', 1), ('Kind,', 1), ('komm', 1),
('geh', 1), ('mir!', 1)]
Hier fallen die Satzzeichen auf, die problematisch werden können. Uns interessiert nicht
wirklich, wie viele Gedankenstriche vorkommen und Satzzeichen beim Wort oben wie im
Beispiel „Gesicht?“. Also beseitigen wir die Satzzeichen komplett:
© https://www.python-lernen.de/nltk-bibliothek-natural-language-toolkit.htm Seite 237
import nltk
satzzeichen = (",", ";", ":", ".", "?", "!", '"', '-', '–')
bereinigt = inhalt.split()
worthaeufigkeit = nltk.FreqDist(bereinigt)
print(worthaeufigkeit.most_common())
Jetzt bekommen wir die Auswertung der Worthäufigkeiten, die wir über die Angabe in der
Klammer auf eine gewünschte Ausgabeanzahl über
print(worthaeufigkeit.most_common(20)) einschränken können. Für die gesamte
Ballade die Häufigkeit der ersten 20 Begriffe:
[('Vater', 9), ('und', 7), ('mit', 6), ('Mein', 6), ('du', 6), ('Kind', 5), ('mein', 5), ('so', 4), ('den', 4), ('Sohn',
4), ('nicht', 4), ('mir', 4), ('Erlkönig', 3), ('Er', 3), ('hat', 3), ('er', 3), ('ich', 3), ('Meine', 3), ('Töchter', 3),
('dich', 3)]
Dies hier als kleine Einführung in eine extrem umfangreiche Bibliothek. Viele Informationen
finden sich auf der Website https://www.nltk.org/ des Projekts.
© https://www.python-lernen.de/wordcloud-erstellen-python.htm Seite 239
Über die Bibliothek Wordcloud ist eine einfache Erstellung einer solchen
mit Python schnell erledigt.
Jetzt aber Schritt für Schritt zur Nutzung (und erst einmal die Installation).
Jetzt werden alle benötigten Module installiert, sofern diese im System nicht schon vorhanden
sind. Dazu gehört neben wordcloud zum Beispiel auch numpy und matplotlib :
Installation WordCloud
Nach der Installation können wir mit unserer ersten Wordcloud in Python starten.
Jetzt kommt unser Text, den wir zu einer Wörterwolke umgebaut bekommen wollen:
text = 'Python Kurs: mit Python programmieren lernen für Anfänger und Fortgeschrittene Dieses Python Tutorial entsteht im Rah
text = 'Python Kurs: mit Python programmieren lernen für Anfänger und Fortgeschrittene Dieses Python Tutorial entsteht im Rah
text = 'Python Kurs: mit Python programmieren lernen für Anfänger und Fortgeschrittene Dieses Python Tutorial entsteht im Rah
plt.imshow(wordcloud, interpolation="bilinear")
plt.show()
Natürlich ist die Bemaßung hier wenig sinnvoll. Daher schalten wir diese ab über:
plt.imshow(wordcloud, interpolation="bilinear")
plt.axis("off")
plt.show()
wordcloud = WordCloud(background_color="white").generate(text)
plt.imshow(wordcloud, interpolation="bilinear")
plt.axis("off")
plt.show()
Aus unserer Variablen „uninteressant“ mit den unwichtigen Wörtern erstellen wir über
split() eine Liste:
uninteressant = "und von Der das den wir ist die auf im"
liste_der_unerwuenschten_woerter = nichtinteressant.split()
Und die STOPWORDS werden vor dem Erzeugen der WordCloud geupdatet:
STOPWORDS.update(liste_der_unerwuenschten_woerter)
wordcloud = WordCloud(background_color="white").generate(text)
text = 'Python Kurs: mit Python programmieren lernen für Anfänger und Fortgeschrittene Dieses Python Tutorial entsteht im Rah
nichtinteressant = "und von Der das den wir ist die auf im"
liste_der_unerwuenschten_woerter = nichtinteressant.split()
STOPWORDS.update(liste_der_unerwuenschten_woerter)
wordcloud = WordCloud(background_color="white").generate(text)
plt.imshow(wordcloud, interpolation="bilinear")
plt.axis("off")
plt.show()
Es fällt noch eine gewisse Unschärfe unseres Bildes auf. Diese können wir durch die
Ausgabegröße ändern!
Jetzt wird das Ausgabebild eine Breite von 1920 Pixel haben und eine Höhe von 1080 und
somit scharf dargestellt:
import os
Und nun können wir die Datei laden und den enthaltenen Text in der Variablen text
speichern.
with open("wordcloud-beispieltext.txt") as f:
text = f.read()
Hier ist es egal, ob wir einen kurzen oder langen Text nutzen wie beispielsweise „Faust“ von
Goehte ( https://de.wikisource.org/wiki/Faust_-_Der_Trag%C3%B6die_erster_Teil ) mit
lockeren 8300 Zeilen.
Wir erhalten innerhalb von ein paar Sekunden dann folgende Ausgabe:
© https://www.python-lernen.de/wordcloud-erstellen-python.htm Seite 243
with open("wordcloud-beispieltext.txt") as f:
text = f.read()
nichtinteressant = "und von Der das den wir ist die auf im"
liste_der_unerwuenschten_woerter = nichtinteressant.split()
STOPWORDS.update(liste_der_unerwuenschten_woerter)
wordcloud = WordCloud(background_color="white",width=1920, height=1080).generate(text)
plt.imshow(wordcloud, interpolation="bilinear")
plt.axis("off")
plt.show()
max_font_size=40
Maximale Schriftgröße
max_words=500
Maximale Anzahl der angezeigten Wörter
Viele weitere Parameter gibt es auf der Seite des Entwicklers unter:
https://amueller.github.io/word_cloud/
Dazu erstellen wir eine Maske, die wir dem Aufruf mitgeben.
© https://www.python-lernen.de/wordcloud-erstellen-python.htm Seite 244
import numpy as np
x, y = np.ogrid[:1000, :1000]
Das Zweipersonen-Spiel wird auf einem Spielfeld mit 3x3 Feldern gespielt. Wer es nicht kennt.
Abwechselnd setzt jeder Spieler seine Marke (X und O) in ein freies Feld. Wer als erstes 3
Felder belegt, die in einer Reihe oder Spalte oder in der Diagonale liegen, gewinnt.
Hier lernt man, wie man ein Spiel in Python programmiert und die Spiellogik integriert.
Dazu wird der Ablauf in mehrere Teile aufgeteilt um das Lernen zu vereinfachen. Durch
folgende Schritte bauen wir das Spiel auf.
Spielfigur setzen
Python-Datei erstellen
Als erstes erstellen wir eine Datei mit dem Dateinamen „tic-tac-toe.py“ und lassen die
Spielnamen ausgeben:
# Spiel Tic-Tac-Toe
print("Tic-Tac-Toe Python Tutorial")
© https://www.python-lernen.de/tic-tac-toe-spielfeld.htm Seite 246
Listen fangen immer mit dem Index 0 an der in Python auch erstellt werden muss. Die Position
0 ist für uns im folgenden Verlauf eher irritierend, daher erstellen wir zwar eine Position 0, die
wir aber im folgenden Spielverlauf nicht nutzen! Diese Liste wird mit den Werten gefüllt, die der
Spieler später als Position für das Belegen mit seiner Spielfigur auswählen kann. Diese Zahlen
werden ausgegeben. So ist bei der Ausgabe sichtbar, welche Zahl gedrückt werden muss, um
das entsprechende Feld zu wählen.
Ausgabe Spielfeld
Wir lassen uns das Spielfeld ausgeben über print() :
# Spielfeld ausgeben
print (spielfeld[1] + "|" + spielfeld[2] + "|" + spielfeld[3] )
print (spielfeld[4] + "|" + spielfeld[5] + "|" + spielfeld[6] )
print (spielfeld[7] + "|" + spielfeld[8] + "|" + spielfeld[9] )
Da im Spiel das Spielfeld nach jedem Zug eines Spielers wieder neu ausgegeben werden muss,
packen wir dies in eine Funktion (siehe funktionen-in-python.htm ) und rufen diese dann für die
Ausgabe auf.
# Spielfeld ausgeben
def spielfeld_ausgeben():
print (spielfeld[1] + "|" + spielfeld[2] + "|" + spielfeld[3] )
print (spielfeld[4] + "|" + spielfeld[5] + "|" + spielfeld[6] )
print (spielfeld[7] + "|" + spielfeld[8] + "|" + spielfeld[9] )
spielfeld_ausgeben()
Das Spielfeld wird nach jedem Zug eines Spielers wieder neu in der Console ausgegeben. Das
mag im ersten Augenblick ungewohnt erscheinen, ist aber bisher unsere einzige Möglichkeit.
In einem späteren Kapitel lernen wir Möglichkeiten kennen, einen Spielzug auf ein bestehendes
Spielbrett zu „zeichnen“. Die bisherige Vorgehensweise ist Ok, da wir ein Spiel programmieren
möchten mit den bisher bekannten Python-Befehlen.
© https://www.python-lernen.de/tic-tac-toe-spielzug-erfassen.htm Seite 247
Wichtig zu berücksichtigen ist, dass wir durch input() ein String zurückgeliefert bekommen.
Lassen wir diesen zum Testen uns ausgeben:
Das ist in diesem Fall wenig hilfreich. Daher wandeln wir diese Eingabe in eine Ganzzahl um.
Python stellt uns für das Umwandeln (Englisch „casting“) entsprechende Anweisungen zur
Verfügung:
Jetzt sollten wir noch sicher gehen, dass eine Zahleneingabe erfolgt, die auch ein Feld
repräsentiert – also irgendwas zwischen 1 und 9. Ansonsten muss eine Meldung erscheinen
und eine weitere Spielereingabe angefordert werden. Hier sperren wir unser Input in eine
while -Schleife ( while-schleife.htm ). Solange dieses nicht entsprechend erfüllt ist, kommt
immer wieder die Benutzerangabe.
Wir erstellen uns eine eigene Funktion für die Benutzereingabe. In dieser wird die Eingabe
kontrolliert und nur mögliche Züge (Eingaben) werden zugelassen.
def spieler_eingabe():
# Eingabe durch Spieler und Überprüfung
Wir wollen so lange vom Spieler eine Eingabe, solange diese nicht korrekt ist. Daher packen wir
diese Aktion in eine unendliche Schleife:
def spieler_eingabe():
while True:
spielzug = input("Bitte Feld eingeben: ")
Um sicherzustellen, dass die richtige Eingabe reinkommt, kontrollieren wir im ersten Schritt
durch eine except , ob es sich um einen nummerischen Wert handelt:
def spieler_eingabe():
while True:
spielzug = input("Bitte Feld eingeben: ")
try:
spielzug = int(spielzug)
except ValueError:
print("Bitte Zahl von 1 bis 9 eingeben")
else:
return spielzug
Im zweiten Schritt kontrollieren wir, ob es sich um eine Zahl zwischen 1 und 9 handelt:
© https://www.python-lernen.de/tic-tac-toe-spielzug-erfassen.htm Seite 248
def spieler_eingabe():
while True:
spielzug = input("Bitte Feld eingeben: ")
try:
spielzug = int(spielzug)
except ValueError:
print("Bitte Zahl von 1 bis 9 eingeben")
else:
if spielzug >= 1 and spielzug <= 9:
return spielzug
else:
print("Zahl muss zwischen 1 und 9 liegen")
# Spiel Tic-Tac-Toe
print("Tic-Tac-Toe Python Tutorial")
# Spielfeld ausgeben
def spielfeld_ausgeben():
print (spielfeld[1] + "|" + spielfeld[2] + "|" + spielfeld[3] )
print (spielfeld[4] + "|" + spielfeld[5] + "|" + spielfeld[6] )
print (spielfeld[7] + "|" + spielfeld[8] + "|" + spielfeld[9] )
spielfeld_ausgeben()
Bisher läuft unser Spiel genau eine Runde. Das ist nicht wirklich ein amüsantes Spiel – und das
Wort kurzweilig trifft es auch nicht wirklich. Wir wollen, dass unser Spiel so lange läuft, bis
entweder ein Spieler gewonnen hat, es unentschieden steht oder das Spiel vorzeitig durch
Spieler bewusst beendet wurde.
Bevor wir in unser Spiel eine Schleife einbauen, damit es nicht nach 1 Runde bereits
automatisch beendet wird, bauen wir als Erstes die Möglichkeit ein, dass ein Spieler gezielt
selber das Spiel beenden kann. Diese Funktion benötigen wir auf jeden Fall - und sobald unser
Spiel unendlich lang läuft, ist man froh über die Abbruchmöglichkeit
beenden kann. Gibt der Spieler also anstelle einer Zahl von 1 bis 9 den Buchstaben „q“ ein, soll
das Spiel beendet werden. Dazu erweitern wir die Funktion spieler_eingabe() um eine
entsprechende if -Abfrage.
Allerdings passt da nicht viel, da unser Spiel bisher sowieso nach einer Eingabe beendet wird.
Wir benötigen also eine Schleife, die entweder am Spielende oder durch den Spieler beendet
wird.
Hauptroutine notwendig
Diese Schleife ist eigentlich das Hauptprogramm und umfasst später alle Aktion wie
Spielfeld ausgeben
Spielereingabe aktivieren
while spiel_aktiv:
# aktuelles Spielfeld ausgeben
spielfeld_ausgeben()
# Eingabe des aktiven Spielers
spielzug = spieler_eingabe()
print("Spielzug: " + str(spielzug))
Das Spiel läuft so lange, solange die Variable spiel_aktiv den Wert True enthält.
Starten wir das Spiel nun, erhalten wir eine Fehlermeldung mit der Ausgabe „NameError: name
spiel_aktiv“ ist nicht definiert.
Für den guten Stil aktivieren wir alle benötigen Variablen am Anfang von unserem Programm
als ersten Schritt:
# Spiel Tic-Tac-Toe
print("Tic-Tac-Toe Python Tutorial")
spiel_aktiv = True
Und die am Anfang gesetzte Variable spiel_aktiv setzen wir auf False , wenn der Spieler
das Spiel vorzeitig durch q beendet. Wichtig ist, dass wir am Anfang der Funktion die
verwendete Variable spiel_aktiv auf global setzen.
while spiel_aktiv:
# Eingabe des aktiven Spielers
spielzug = spieler_eingabe()
if spielzug:
spielfeld[spielzug] = 'X'
# aktuelles Spielfeld ausgeben
spielfeld_ausgeben()
Allerdings haben wir noch gar keinen zweiten Spieler bzw. den Wechsel von Spieler X zu
Spieler O.
Also brauchen wir ganz am Anfang wieder eine Variable für den aktuellen Spieler
spieler_aktuell . Diesen lassen wir auch vor der Eingabe durch den Spieler am Bildschirm
ausgeben:
# Spiel Tic-Tac-Toe
print("Tic-Tac-Toe Python Tutorial")
spiel_aktiv = True
spieler_aktuell = 'X'
while spiel_aktiv:
# Eingabe des aktiven Spielers
print ("Spieler " + spieler_aktuell + " am Zug")
spielzug = spieler_eingabe()
if spielzug:
spielfeld[spielzug] = spieler_aktuell
# aktuelles Spielfeld ausgeben
spielfeld_ausgeben()
automatischer Spielerwechsel
Jetzt benötigen wir einen automatischen Wechsel des Spielers nach jedem Spielzug. Dazu
erstellen wir eine Funktion mit dem Namen spieler_wechseln() . Dabei darf man nicht
vergessen, die Variable spieler_aktuell auf global zu setzen.
def spieler_wechseln():
global spieler_aktuell
if spieler_aktuell == 'X':
spieler_aktuell = 'O'
else:
spieler_aktuell = 'X'
Diese Funktion rufen wir nach der Ausgabe von Spielfeld in unserer Hauptschleife auf:
© https://www.python-lernen.de/tic-tac-toe-spielfigur-setzen.htm Seite 252
while spiel_aktiv:
# Eingabe des aktiven Spielers
print ("Spieler " + spieler_aktuell + " am Zug")
spielzug = spieler_eingabe()
if spielzug:
# spielfeld[spielzug] = 'X'
spielfeld[spielzug] = spieler_aktuell
# aktuelles Spielfeld ausgeben
spielfeld_ausgeben()
# Spieler wechseln
spieler_wechseln()
# Spiel Tic-Tac-Toe
print("Tic-Tac-Toe Python Tutorial")
spiel_aktiv = True
spieler_aktuell = 'X'
# Spielfeld ausgeben
def spielfeld_ausgeben():
print (spielfeld[1] + "|" + spielfeld[2] + "|" + spielfeld[3] )
print (spielfeld[4] + "|" + spielfeld[5] + "|" + spielfeld[6] )
print (spielfeld[7] + "|" + spielfeld[8] + "|" + spielfeld[9] )
def spieler_wechseln():
global spieler_aktuell
if spieler_aktuell == 'X':
© https://www.python-lernen.de/tic-tac-toe-spielfigur-setzen.htm Seite 253
if spieler_aktuell == 'X':
spieler_aktuell = 'O'
else:
spieler_aktuell = 'X'
Dies wird nun kontrolliert. Dazu müssen einfach in den entsprechenden 3 Feldern der gleiche
Inhalt vorliegen (sprich entweder dreimal X oder dreimal O). Dazu erstellen wir die Funktion
kontrolle_gewonnen() .
while spiel_aktiv:
# Eingabe des aktiven Spielers
print ("Spieler " + spieler_aktuell + " am Zug")
spielzug = spieler_eingabe()
if spielzug:
# spielfeld[spielzug] = 'X'
spielfeld[spielzug] = spieler_aktuell
# aktuelles Spielfeld ausgeben
spielfeld_ausgeben()
# Kontrolle, ob jemand gewonnen hat
gewonnen = kontrolle_gewonnen()
if gewonnen:
print ("Spieler " + gewonnen + " hat gewonnen!")
spiel_aktiv = False
# Spieler wechseln
spieler_wechseln()
# Kontrolle, ob unentschieden
unentschieden = kontrolle_auf_unentschieden()
if unentschieden:
print ("Spiel ist unentschieden ausgegangen")
spiel_aktiv = False
def kontrolle_auf_unentschieden():
if (spielfeld[1] == 'X' or spielfeld[1] == 'O') \
and (spielfeld[2] == 'X' or spielfeld[2] == 'O') \
and (spielfeld[3] == 'X' or spielfeld[3] == 'O') \
and (spielfeld[4] == 'X' or spielfeld[4] == 'O') \
and (spielfeld[5] == 'X' or spielfeld[5] == 'O') \
and (spielfeld[6] == 'X' or spielfeld[6] == 'O') \
and (spielfeld[7] == 'X' or spielfeld[7] == 'O') \
and (spielfeld[8] == 'X' or spielfeld[8] == 'O') \
and (spielfeld[9] == 'X' or spielfeld[9] == 'O'):
return ('unentschieden')
# Spiel Tic-Tac-Toe
print("Tic-Tac-Toe Python Tutorial")
spiel_aktiv = True
spieler_aktuell = 'X'
# Spielfeld als Liste erstellen
spielfeld = [" ",
"1","2","3",
© https://www.python-lernen.de/tic-tac-toe-kontrolle-gewonnen.htm Seite 256
"1","2","3",
"4","5","6",
"7","8","9"]
# Spielfeld ausgeben
def spielfeld_ausgeben():
print (spielfeld[1] + "|" + spielfeld[2] + "|" + spielfeld[3] )
print (spielfeld[4] + "|" + spielfeld[5] + "|" + spielfeld[6] )
print (spielfeld[7] + "|" + spielfeld[8] + "|" + spielfeld[9] )
def spieler_wechseln():
global spieler_aktuell
if spieler_aktuell == 'X':
spieler_aktuell = 'O'
else:
spieler_aktuell = 'X'
def kontrolle_auf_unentschieden():
if (spielfeld[1] == 'X' or spielfeld[1] == 'O') \
and (spielfeld[2] == 'X' or spielfeld[2] == 'O') \
and (spielfeld[3] == 'X' or spielfeld[3] == 'O') \
and (spielfeld[4] == 'X' or spielfeld[4] == 'O') \
and (spielfeld[5] == 'X' or spielfeld[5] == 'O') \
and (spielfeld[6] == 'X' or spielfeld[6] == 'O') \
and (spielfeld[7] == 'X' or spielfeld[7] == 'O') \
and (spielfeld[8] == 'X' or spielfeld[8] == 'O') \
and (spielfeld[9] == 'X' or spielfeld[9] == 'O'):
return ('unentschieden')
Dazu erweitern wir unsere Exception entsprechend und überprüfen das vom Spieler
gewünschte Feld, ob sich dort bereits ein Eintrag befindet. Dies erfolgt über eine if -Abfrage
in der Form:
Im Python-Code integriert:
# Spiel Tic-Tac-Toe
print("Tic-Tac-Toe Python Tutorial")
spiel_aktiv = True
spieler_aktuell = 'X'
© https://www.python-lernen.de/tic-tac-toe-kontrolle-spielzug.htm Seite 259
spieler_aktuell = 'X'
# Spielfeld als Liste erstellen
spielfeld = [" ",
"1","2","3",
"4","5","6",
"7","8","9"]
# Spielfeld ausgeben
def spielfeld_ausgeben():
print (spielfeld[1] + "|" + spielfeld[2] + "|" + spielfeld[3] )
print (spielfeld[4] + "|" + spielfeld[5] + "|" + spielfeld[6] )
print (spielfeld[7] + "|" + spielfeld[8] + "|" + spielfeld[9] )
# Spieleingabe und Kontrolle der Eingabe
def spieler_eingabe():
global spiel_aktiv
while True:
spielzug = input("Bitte Feld eingeben: ")
# vorzeitiges Spielende durch Spieler
if spielzug == 'q':
spiel_aktiv = False
return
try:
spielzug = int(spielzug)
except ValueError:
print("Bitte Zahl von 1 bis 9 eingeben")
else:
if spielzug >= 1 and spielzug <= 9:
if spielfeld[spielzug] == 'X' or spielfeld[spielzug] == 'O':
print("Das Feld ist bereits belegt - ein anderes wählen!")
else:
return spielzug
else:
print("Zahl muss zwischen 1 und 9 liegen")
def spieler_wechseln():
global spieler_aktuell
if spieler_aktuell == 'X':
spieler_aktuell = 'O'
else:
spieler_aktuell = 'X'
# Kontrolle, ob ein Spieler gewonnen hat
def kontrolle_gewonnen():
# wenn alle 3 Felder gleich sind, hat der entsprechende Spieler gewonnen
# Kontrolle auf Reihen
if spielfeld[1] == spielfeld[2] == spielfeld[3]:
return spielfeld[1]
if spielfeld[4] == spielfeld[5] == spielfeld[6]:
return spielfeld[4]
if spielfeld[7] == spielfeld[8] == spielfeld[9]:
return spielfeld[7]
# Kontrolle auf Spalten
if spielfeld[1] == spielfeld[4] == spielfeld[7]:
return spielfeld[1]
if spielfeld[2] == spielfeld[5] == spielfeld[8]:
return spielfeld[2]
if spielfeld[3] == spielfeld[6] == spielfeld[9]:
© https://www.python-lernen.de/tic-tac-toe-kontrolle-spielzug.htm Seite 260
def kontrolle_auf_unentschieden():
if (spielfeld[1] == 'X' or spielfeld[1] == 'O') \
and (spielfeld[2] == 'X' or spielfeld[2] == 'O') \
and (spielfeld[3] == 'X' or spielfeld[3] == 'O') \
and (spielfeld[4] == 'X' or spielfeld[4] == 'O') \
and (spielfeld[5] == 'X' or spielfeld[5] == 'O') \
and (spielfeld[6] == 'X' or spielfeld[6] == 'O') \
and (spielfeld[7] == 'X' or spielfeld[7] == 'O') \
and (spielfeld[8] == 'X' or spielfeld[8] == 'O') \
and (spielfeld[9] == 'X' or spielfeld[9] == 'O'):
return ('unentschieden')
Im Tutorial soll einfach gezeigt werden, wo man eingreifen muss, um den zweiten Spieler
durch eine KI (bzw. KD) ersetzen zu lassen:
while spiel_aktiv:
# Eingabe des aktiven Spielers
print()
print ("Spieler " + spieler_aktuell + " am Zug")
# aus der Liste spielfeld alle X und O und leere Felder entfernen
spielfeld_KI = []
for moegliche_felder in spielfeld:
if moegliche_felder != 'X' and moegliche_felder != 'O' and moegliche_felder
spielfeld_KI += moegliche_felder
# print (spielfeld_KI)
# print()
# print(random.choice(spielfeld_KI))
In Python ist ein Turtle-Modul integriert, dass man nach dem Import nutzen kann. Hier eine
kleine Einführung und danach setzen wir das Modul zum Zeichnen einer Benutzeroberfläche
für ein Spiel ein.
import turtle
import turtle
turtle.forward(200)
Unsere Turtle wird exakt mittig auf dem Ausgabebildschirm platziert. Dort sind die X und Y
Koordinaten von 0.
Die Schildkröte schaut nach rechts und mit der Anweisung vorwärts ( turtle.forward )
bewegt sich um die angegebene Pixelanzahl nach rechts.
unsere Turtle (Schildkröte) wird genau mittig platziert und bewegt sich um 200 Pixel
Was sich vorwärts bewegen kann, kann sich auch rückwärts bewegen. Das funktioniert mit der
Anweisung turtle.backward
© https://www.python-lernen.de/python-turtle.htm Seite 263
turtle.right(90)
turtle.left(120)
turtle.color('yellow')
turtle.width(10)
turtle.bgcolor('black')
gefülltes Dreieck
import turtle
turtle.bgcolor('black')
turtle.color('yellow')
turtle.width(10)
turtle.begin_fill()
turtle.forward(100)
turtle.right(90)
turtle.forward(100)
turtle.color('orange')
turtle.end_fill()
import turtle
turtle.bgcolor('black')
turtle.color('yellow')
turtle.circle(100)
turtle.goto(250,250)
turtle.color('orange')
turtle.circle(100)
Allerdings wird ein Strich zwischen dem Endpunkt und dem neuen über goto
angesprungenen Anfangspunkt gezeichnet. Dies können wir über folgende 2 Befehle up()
und down() vermeiden.
turtle.color('yellow')
turtle.circle(100)
turtle.up()
turtle.color('orange')
turtle.forward(150)
turtle.down()
turtle.circle(100)
Anstelle die Turtle über forward zu bewegen, kann auch der Befehl goto eingesetzt
werden.
Und wer es perfekt machen möchte, kann die Verschlungenheit der Ringe korrekt darstellen :)
import turtle
turtle.write('Hallo Welt')
Parameters:
bewegen – True/False
turtle.clear()
Soll sowohl der Bildschirm gelöscht werden wie auch alle Variablen zurückgestellt werden,
dann hilft reset()
turtle.reset()
© https://www.python-lernen.de/main-python.htm Seite 266
Was passiert aber, wenn in der importierten Datei neben den Funktionen auch direkt
ausführbarer Code enthalten ist?
def bspfunktionfuerrueckgabe(eingabewert):
rueckgabewert = eingabewert * 2
return rueckgabewert
Dann wird immer genau an der Stelle, wo diese Datei importiert wird auch zusätzlich der im
Beispiel eingebaute print -Befehl ausgeführt.
Daher gibt es den Main-Bereich. Diesen erzeugen wir, indem wir den Dateinamen mit dem
Systemwert __main__ vergleichen. Den Dateinamen erhalten wir über __name__
Wenn wir uns den Inhalt von __name__ ausgeben lassen, werden wir feststellen, dass wir bei
direktem Aufruf als Rückgabewert __main__ erhalten. Bei indirektem Aufruf erhalten wir den
Dateinamen!
print(__name__)
__main__
Packen wir nun unseren Programmcode in eine andere Datei mit dem Namen
„fktsammlung.py“. Hier deutet sich auch die Funktion der „externen“ Datei an - wir haben dort
eine Sammlung von Funktionen, die wir immer wieder verwenden können. Dann wird der Wert
von __name__ den Dateinamen der importierten Datei enthalten.
Um jetzt überprüfen zu können, ob eine Datei direkt ausgeführt wird, werden beide
Systemkonstanten in eine if -Bedingung gepackt. So wissen wir, ob die Datei direkt
aufgerufen wird und somit der Code ausgeführt werden soll oder diese importiert wurde uns
somit nur die Funktionen zur Verfügung stehen sollen.
def bspfunktionfuerrueckgabe(eingabewert):
rueckgabewert = eingabewert * 2
return rueckgabewert
if __name__ == "__main__":
print("Datei wurde direkt aufgerufen und die Main wird ausgeführt")
else:
print("Datei wurde als Modul aufgerufen")
Nutzen wir nun dieses Programm als Modul und rufen dieses über eine andere Datei auf (siehe
letzte Kapitel) erhalten wir die entsprechende Ausgabe.
import fktsammlung
fktsammlung.bspfunktionfuerrueckgabe(3)
Die Datei selber, die wir mit Python laden wollen, sollte sich im gleichen Verzeichnis befinden.
Wir erstellen uns eine Textdatei mit dem Inhalt „Text, der aus Datei kommt“. Der Dateinamen
sollte den üblichen Kriterien entsprechen. Es muss nicht einmal eine Dateiendung vergeben
werden – ich mache dies rein aus Gewohnheit und nenne meine Textdatei „textdatei.txt“.
Um diese Datei nun zu laden, erstellen wir ein Python-Programm im gleichen Verzeichnis, in
der sich auch unsere Textdatei befindet.
open('textdatei.txt', MODUS)
Bisher passiert noch nichts, da wir die Art der Verwendung bei open im MODUS angeben
müssen. Es gibt verschiedene Modi, um eine Datei zu lesen, in eine Datei zu schreiben bzw.
gleichzeitiges lesen und schreiben.
b In Binärform für Lesen und Schreiben (die anderen Modi werden durch b ergänzt)
Wir wollen jetzt erst einmal unseren Inhalt aus der Datei lesen, also verwenden wir den „nur
lesen“-Modus r .
open('textdatei.txt','r')
Soweit so gut. Was liefert uns eigentlich die Funktion open zurück? Diese liefert uns einen
Rückgabewert zurück, auf den wir dann verschiedene Methoden anwenden können.
datei = open('textdatei.txt','r')
print(datei)
Jetzt können wir die zur Verfügung stehende Methoden darauf anwenden wie z.B. read .
datei = open('textdatei.txt','r')
print(datei.read())
Wir erhalten nun den Inhalt „Text, der aus Datei kommt“ angezeigt.
Erweitern wir nun den Inhalt unserer Datei „textdatei.txt“ um 2 weitere Zeilen:
© https://www.python-lernen.de/dateien-auslesen.htm Seite 269
Speichern nicht vergessen. Wenn wir nun wieder unsere Methode read darauf anwenden,
sehen wir als Ergebnis den kompletten Inhalt (egal wie viele Zeilen es sind).
datei = open('textdatei.txt','r')
print(datei.readline())
Um jetzt Zeile für Zeile einzulesen, packen wir die readline() Methode in eine for -
Schleife:
datei = open('textdatei.txt','r')
for zeile in datei:
print("Inhalt aus Datei: ")
print(zeile)
datei = open('textdatei.txt','r')
print(datei.read(7))
Als Ergebnis erhalten wir nun von unserem Mustertext als Rückgabe die ersten sieben Zeichen:
Text, d
Wäre das siebte Zeichen ein Zeilenumbruch, würde dieses dann als letztes Zeichen gelesen
und ausgegeben. Einfach einmal probieren :).
datei = open('textdatei.txt','r')
print(datei.read())
datei.close()
© https://www.python-lernen.de/in-dateien-schreiben.htm Seite 271
datei = open('textdatei.txt','r')
print(datei.read())
Im ersten Schritt müssen wir den Modus ändern, wie die Datei bei dem Befehl open geöffnet
wird. Es stehen und für das Schreiben die Methoden 'w', 'a' und 'r+' zur Verfügung.
Zum Testen verwenden wir den Modus 'a' für „append“ um Inhalt an eventuell bestehenden
Inhalt anzuhängen.
datei = open('textdatei.txt','a')
datei.write("weitere Zeile")
Wenn wir nun das Programm ausführen lassen, erhalten wir keinerlei sichtbare Reaktion. Wenn
wir nun in unsere Datei „textdatei.txt“ sehen, wurde für jedes ausführen des Python-
Programms der Text „weitere Zeile“ in die Datei zu dem bestehenden Text hinzugefügt.
Der Text wird einfach am bestehenden Text am Ende angefügt. Ohne eine neue Zeile! Lassen
wir das Programm zweimal ausführen, steht dann in der Datei hintereinander ohne Umbruch
und ohne Leerzeichen:
Wir haben also keine weitere Zeile erstellt, sondern Text an eine bestehende Zeile angehängt.
datei = open('textdatei.txt','r')
datei.write("\r\nweitere Zeile")
Wir fügen vor unserem Text den Zeilenumbruch hinzu. Lassen wir nun unser Programm 2-mal
ausführen, erhalten wir wie gewünscht in der Datei das Ergebnis mit Zeilenumbruch:
weitere Zeile
weitere Zeile
datei = open('textdatei.txt','w')
datei.write("\r\nweitere Zeile")
© https://www.python-lernen.de/in-dateien-schreiben.htm Seite 272
Lassen wir nun unser Programm ausführen, erhalten wir im Ergebnis nur noch die Zeile. Alle
alten Inhalte wurden "überschrieben".
weitere Zeile
datei = open('textdatei.txt','r+')
datei.write("\r\nweitere Zeile")
print(datei.read())
Sollte nun nichts als Ausgabe erscheinen, dann sieht man das Problem bei 'r+'. Wir lesen
schneller aus, als in die Datei geschrieben wurde bzw. das System puffert und daher kommt
Chaos. Daher kommt nichts in der Ausgabe. Daher den Modus 'r+' nur mit Vorsicht nutzen! Hier
hilft das Schließen der Verbindung über die Methode close() . Allerdings muss dann auch
die Datei wieder geöffnet werden.
datei = open('textdatei.txt','r+')
datei.write("\r\nweitere Zeile")
datei.close()
datei = open('textdatei.txt','r+')
print(datei.read())
datei.close()
Lesen/Schreiben binär
Sollten wir nun mit binären Daten arbeiten, dann ist als Modus 'b' angesagt, der an das primäre
Kürzel angehängt wird.
datei = open('textdatei.txt','wb')
datei = open('textdatei.txt','rb')
© https://www.python-lernen.de/csv-datei-einlesen.htm Seite 273
C = Comma = Komma
S = separated = getrennte
V = values = Werte
Unsere Daten liegen also durch Kommas voneinander getrennt in einer Datei vor. Meistens sind
in der ersten Linie die Namen der Datenspalten hinterlegt.
nachname,vorname,geburtstag
Müller,Mike,1980-03-05
Sommer,Elke,1987-05-02
Schuster,Johanna,1993-10-10
Allerdings muss man wissen, dass das Trennzeichen nicht zwingend ein Komma sein muss,
aber das Dateiformat weiterhin CSV sich nennt.
Semikolon ;
Doppelpunkt :
TAB \t
Verfügt man über Daten, die in einer Exceltabelle vorliegen, kann man diese direkt aus Excel
heraus im CSV-Format abspeichern. Excel erlaubt zusätzlich die Angabe, welche Trennzeichen
verwendet werden sollen.
Und hier kommt der Vorteil von fertigen Bibliotheken. Einfach nutzen ohne große Probleme.
Zum Testen speichern wir unsere Adressdaten von oben in die Textdatei mit dem Namen
„adressen.csv“.
import csv
import csv
with open('adressen.csv') as csvdatei:
Wir können nun unser Programm ausführen, aber es passiert noch nichts. Wir benötigen unser
csv.reader , der uns aus geöffneten CSV-Datei ein „csv.reader object“ macht:
© https://www.python-lernen.de/csv-datei-einlesen.htm Seite 274
import csv
with open('adressen.csv') as csvdatei:
csv_reader_object = csv.reader(csvdatei, delimiter=',')
print(csv_reader_object)
Unserem csv.reader übergeben wir unsere geöffnete CSV-Datei und können auch das
Trennzeichen über die Anweisung delimiter=',' mitgeben. Als Standard ist das Komma
hinterlegt, daher müssten wir bei einem Komma als Trennzeichen nicht einmal den „delimiter“
festlegen.
import csv
with open('adressen.csv') as csvdatei:
csv_reader_object = csv.reader(csvdatei)
print(csv_reader_object)
Jetzt haben wir unser „csv.reader object“, dass wir über die for … in Konstruktion
durchlaufen und unsere Daten ausgeben können.
import csv
with open("adressen.csv") as csvdatei:
csv_reader_object = csv.reader(csvdatei)
for row in csv_reader_object:
print(row)
Unsere Daten liegen in Form einer Liste vor und können dementsprechend genutzt werden. Als
Ausgabe erhalten wir:
Jetzt können wir noch die erste Zeile abfangen und unsere Daten nutzen. Unser kompletter
Programmcode:
import csv
zeilennummer = 0
for row in csv_reader_object:
if zeilennummer == 0:
print(f'Spaltennamen sind: {", ".join(row)}')
else:
print(f'- Nachname: {row[0]} \t| Vorname: {row[1]} \t| Geburtstag: {row[
zeilennummer += 1
import csv
with open("adressen.csv") as csvdatei:
csv_reader_object = csv.DictReader(csvdatei)
for row in csv_reader_object:
print(row)
Objektorientierte Programmierung ist nicht schwer und macht vieles einfacher! Also einfach
auf das Abenteuer einlassen. Um das sperrige Wort objektorientierte Programmierung zu
vermeiden, verwende ich die geläufige Abkürzung OOP.
Am Rande bemerkt: durch das Verständnis von OOP werden auch die Python Module und die
komplette Sprache sehr viel einfacher verständlich.
OOP ganz einfach: Sprechen wir mal von Dingen (um die Materie greifbar zu machen)
Dinge können Aktionen machen/bzw. mit diesen Dingen gemacht werden wie z.B. knurren,
schmusen und schlafen
Bisher hatten wir in Python entweder Daten (was wir bei unseren Dingen mit Eigenschaften
beschrieben haben) oder wir haben irgendwelche Aufgaben erledigt mit Funktionen und
Methoden (in die wir zeitweise verschiedene Daten reingekippt haben).
Was aber passiert, wenn wir Daten und Methoden miteinander verknüpfen? Dann haben wir
schon objektorientierte Programmierung (OOP) bzw. den Kerngedanken begriffen.
Wir trennen uns von den unspezifischen Datenstrukturen wie Variablen, Listen und Tupeln und
gehen hin zu Datenstrukturen, die ein Objekt (sprich ein Ding) beschreiben.
Schauen wir uns einmal ganz konkret (m)eine Katze an. Die ist orange, fett und frisst nur
Lasagne, falls sie nicht schläft und heißt Garfield. Spaß beiseite, aber es kommt mit dieser
Beschreibung schon relativ gut hin. Überleg einmal, welche Eigenschaften von Katzen einem
einfallen und was Katzen so machen.
Eigenschaften:
hat 4 Beine
Wir bauen uns also ein allgemeines Bild von einer Katze – einen Bauplan. Wir spielen mit
Python Gott und schaffen einen allgemeinen Katzen-Zusammenbau-Plan. Das ist unsere
Katzen-Klasse.
© https://www.python-lernen.de/oop-objektorientierte-programmierung-grundlagen.htm Seite 277
Und nun können wir virtuelle Katzen in beliebiger Anzahl erschaffen – sprich ganz viele Objekte,
die grundlegend Gleich nach dem Bauplan aufgebaut sind, aber sich in Ihren Eigenschaften
(Farbe, Alter, Name) unterscheiden und in der Ausprägung der Methoden.
tut fressen
tut schlafen
tut schmusen
tut fauchen
Unsere Katze kann also, sobald die Methode „fressen()“ aufgerufen wird, den Futternapf leeren
(oder die Maus verspeisen).
Je nach Objekt (nicht jede Katze ist gleich) tut (sprich wird eine Methode angewendet) eine
Katze spielen, schmusen oder fauchen – muss aber nicht. Prinzipiell wäre es nach der
Katzenklasse möglich.
Klasse Objekt
© https://www.python-lernen.de/oop-objektorientierte-programmierung-grundlagen.htm Seite 278
Klasse Objekt
Eigenschaften: Objekt:
Alter 3
Rufname Sammy
Methoden: Methoden:
miauen miauen()
schlafen schlafen()
fressen fressen()
schmusen schmusen()
Allgemeine Beschreibung, die Blaupause (Klassen definieren Objekte haben konkrete Werte
Objekte)
Aus der Klasse können wir noch jede Menge weitere Objekte machen. „Machen“ hört sich nicht
wirklich professionell an, daher spricht man bei der OOP von Instanzen erstellen bzw.
instanziieren.
Instanz (nichts anderes wie ein Objekt – Lateinische Begriffe hören sich einfach hipper an – die
lateinische Bedeutung ist „abgeschlossene Einheit“)
Ähnlich wie bei einem Erbfall bekommt der Erbende etwas vom Verblichenen. Allerdings muss
bei der Programmierung nichts sterben.
Bleiben wir bei unserem Katzenbeispiel. Eine Katze ist schon sehr konkret (was man
spätestens beim Einsatz der Krallen spürt). Hier können wir noch einen Schritt davor machen.
Wir können uns eine allgemeine Klasse „Tier“ vorstellen. So ein Tier hat wie die Katze „Farbe,
Alter, Bezeichnung“ und „frisst und schläft“ normalerweise. Es ist eine allgemeine Sichtweise.
Wir können nun eine Klasse „Tier“ erzeugen, was diese Eigenschaften und Methoden hat.
Sprich unsere Klasse „Katze“ kann von der Klasse „Tier“ diese Eigenschaften und Methoden
erben und die Katzen-Klasse benötigt dann nur noch die fehlenden Eigenschaften und
Methoden (nicht jedes Tier kann schmusen oder hat Krallen für das Gegenteil).
Man spart sich also Programmierarbeit. Zumal wir aus der Klasse Tier auch eine Klasse Hund
erstellen können. Auch der Hund hat alle Eigenschaften und Methoden von der Klasse Tier.
Um einen letzten Begriff noch einzuführen. Passt etwas bei der Vererbung nicht, dann kann
man es in der Realität einfach nicht annehmen oder wegwerfen. Beim Programmieren dagegen
kann man diese Eigenschaft bzw. Methode „überschreiben“. Viele Möglichkeiten die dann beim
Programmieren eine konkrete Welt als binäre Welt abbilden lassen.
Das soll soweit erst einmal als grundlegendes Verständnis der OOP reichen. Diese werden in
den folgenden Kapiteln noch deutlich klarer, wenn wir diese konkret an Beispielen nutzen.
In den folgenden Kapiteln schauen wir uns also an, wie wir in Python Klassen aufbauen und
daraus Instanzen bilden (sprich Objekte wie die Katze Sammy erstellen).
© https://www.python-lernen.de/klassen-in-python.htm Seite 280
Klassen in Python
Nun starten wir mit Python und klassenorientierter Programmierung.
Wir definieren eine Klasse. Die Definition von Klassen muss vor dem Hauptprogramm im Code
stehen. Zur Erinnerung aus dem letzten Kapitel: Klassen sind Baupläne, aus denen dann später
die Objekte erstellt werden.
Starten wir einfach, denn am Beispiel wird die Funktion und die Vorteile klar.
Also nennen wir das Kind beim Namen. In vielen Kursen und später
bei gewohntem Umgang mit Klassen und objektorientierter
Programmierung wird man den Klassennamen sehr kurz und
aussagekräftig halten – dann würde man etwas in die Richtung
class Katze festlegen. Zum Lernen werde ich den etwas
sperrigeren Klassennamen BauplanKatzenKlasse einsetzen.
class BauplanKatzenKlasse():
Was fällt auf? Der Klassenname startet mit einem Großbuchstaben! So erkennt man bereits am
Namen, dass es sich um eine Klasse handeln muss! Sind es mehrere Worte, werden diese über
die UpperCamelCase-Variante zusammengeschrieben. Wer ein deutsches Wort dafür benötigt
– Binnenmajuskel :) – Großbuchstaben mitten im Wort wie bei den Kamelhöckern. Leerzeichen
und Unterstriche werden auf keinen Fall genutzt! (Siehe Spickzettel zum Thema Konventionen
und Schreibweisen)
Nach dem Klassennamen folgt eine öffnende und schließende runde Klammer und dann der
Doppelpunkt, den man gerne einmal versehentlich vergisst.
Eine kleine Beschreibung gleich nach der Klassendefinition mitzugeben, macht sehr viel Sinn.
Diese Beschreibung taucht bei der Nutzung von help(Klassenname) wieder auf. Diese
Hilfen kennt man von allen Befehlen von Python, die man aufrufen kann über help(befehl) .
Diese Hilfen sind auch wichtig, wenn man mit mehreren Programmierern an einem Projekt
arbeitet bzw. wenn man seine Klassen weitergeben möchte oder an einem schlechten
Gedächtnis leidet.
Wie sieht das im Code aus? Nach der ersten Zeile mit class … starten wir in der nächsten
Zeile eingerückt mit 3 doppelten Anführungszeichen – das nennt sich Docstring
(Dokumentationsstring). Abgeschlossen wird der Hilfetext mit 3 doppelten Anführungszeichen.
class BauplanKatzenKlasse():
""" Klasse für das Erstellen von Katzen
Hilfetext ideal bei mehreren Programmierern in
einem Projekt oder bei schlechtem Gedächtnis """
Um uns die Hilfe einmal ausgeben lassen zu können, geben wir noch in unserem Programm die
folgende help -Zeile ein:
© https://www.python-lernen.de/klassen-in-python.htm Seite 281
class BauplanKatzenKlasse():
""" Klasse für das Erstellen von Katzen
Hilfetext ideal bei mehreren Programmierern in
einem Projekt oder bei schlechtem Gedächtnis """
print(help(BauplanKatzenKlasse))
class BauplanKatzenKlasse(builtins.object)
| Klasse für das Erstellen von Katzen
| Hilfetext ideal bei mehreren Programmierern in
| einem Projekt oder bei schlechtem Gedächtnis
|
| Data descriptors defined here:
|
| __dict__
| dictionary for instance variables (if defined)
|
| __weakref__
| list of weak references to the object (if defined)
Bisher haben wir nur den Rumpf für unsere Klasse erstellt. Im folgenden Kapitel wollen wir nun
die Eigenschaften festlegen.
© https://www.python-lernen.de/konstruktoren.htm Seite 282
Eigenschaften:
Farbe
Alter
Rufname
Bisher haben wir nur unseren Rumpf unserer Klasse „BauplanKatzenKlasse“ erstellt.
class BauplanKatzenKlasse():
""" Klasse für das Erstellen von Katzen
Hilfetext ideal bei mehreren Programmierern in
einem Projekt oder bei schlechtem Gedächtnis """
Jetzt wollen wir unsere Eigenschaften einführen. Dazu wird ein neuer eingerückter Block
erstellt, der immer den gleichen Aufruf hat: def __init__(self, …): . Folgend für unsere
Katzen-Klasse:
class BauplanKatzenKlasse():
""" Klasse für das Erstellen von Katzen
Hilfetext ideal bei mehreren Programmierern in
einem Projekt oder bei schlechtem Gedächtnis """
Unserer Methode __init__ wird immer mit 2 Unterstrichen am Anfang und am Ende
geschrieben. In der Klammer kommt als erstes Argument immer „self“! Hier kommt ein
wichtiges Prinzip zum Tragen, dass Klassen so stark macht.
Dazu müssen wir kurz vorgreifen und uns ein Objekt erstellen. Bauen wir unsere erste Katze
mit dem Namen „Sammy“, die orange ist und 3 Jahre alt.
class BauplanKatzenKlasse():
""" Klasse für das Erstellen von Katzen
Hilfetext ideal bei mehreren Programmierern in
einem Projekt oder bei schlechtem Gedächtnis """
Wenn wir das Objekt „katze_sammy“ der Klasse „BauplanKatzenKlasse“ erstellen, wird der
Objektname „katze_sammy“ als erstes Argument in die „__init__(self)“ übergeben. Rufen wir
dann später Attribute der Klasse ab, machen wir das wieder über unseren Objektnamen
„katze_sammy“, die über „self.alter“ auf den Wert von Alter zugreift.
© https://www.python-lernen.de/konstruktoren.htm Seite 283
Sehr schön sieht man auch die Auswirkungen unseren bisherigen Codes beim Live-Editor
(python-online-lern-editor.htm):
und in groß:
Jetzt können wir das Alter über unsere Instanz (sprich Objekt) „katze_sammy“ abrufen:
3
© https://www.python-lernen.de/konstruktoren.htm Seite 284
Hier sieht man schön die Gewichtigkeit von self sowohl beim „Befüllen“ unsere Klasse, wie
beim Erzeugen eines Objekts und letztendlich auch immer beim Abruf von Attributen (wie im
Beispiel das Alter oder den Rufnamen).
Wer mag, darf die folgenden Beispiele auch mit Fahrrädern oder was auch immer durchführen.
Erste Überlegung:
Bitte eine Klasse erstellen mit mindestens dem Wert „Farbe“ und ein Objekt erstellen und
darüber die Farbe abrufen.
© https://www.python-lernen.de/loesung-uebung-klasse-auto-erstellen.htm Seite 285
Grundsätzlich kann man sich überlegen, ob die Benennung Auto denn so glücklich ist? Man
kann bei den grundsätzlichen Überlegungen auch weiter verallgemeinern bzw. ähnliches
suchen. Ähnlich wäre der Pkw (der PersonenKraftWagen oder in der Schweiz PW für
PersonenWagen).
Es handelt sich um ein Fahrzeug mit eigenem Antrieb zum Personen befördern. Also kein
Fahrrad, da diese keinen eigenen Antrieb haben. Weiter verallgemeinert wäre es ein
Kraftfahrzeug. Wir könnten also für das Auto die Klasse „Pkw“ wählen.
class Pkw():
""" Klasse für das Erstellen von Personenkraftwagen """
Im nächsten Schritt können wir uns überlegen, welche Eigenschaften wichtig sind. Dabei
bestimmt unsere Anwendung die Auswahl der Eigenschaften. Für bestimmte Menschen ist
zum Beispiel das Material des Interieurs wichtig. Wurzelholz oder kein Wurzelholz – das ist hier
die Frage. Wir halten es allgemeiner und wir wollen die wichtigen Dinge als Eigenschaften. Uns
interessiert neben
das Baujahr
Anzahl Sitzplätze
Marke
class Pkw():
""" Klasse für das Erstellen von Personenkraftwagen """
Aber hier ist wie gesagt die Anwendung wichtig und diese bestimmt die dafür benötigten
Eigenschaften. Ganz außen vor ist gerade PS und Kraftstoffverbrauch.
Und jetzt können wir noch ein Objekt instanziieren – sprich wir basteln uns einen Trabi.
© https://www.python-lernen.de/loesung-uebung-klasse-auto-erstellen.htm Seite 286
class Pkw():
""" Klasse für das Erstellen von Personenkraftwagen """
Als Ergebnis haben wir ein Objekt, mit dem wir nun weiterarbeiten können:
Zum Abrufen der Farbe benötigen wir nach unserer erstellten Klasse mit dem Objekt „trabi“ nur
den Aufruf:
print(trabi.farbe)
© https://www.python-lernen.de/oop-klasse-objekt-instanz-anlegen.htm Seite 287
class BauplanKatzenKlasse():
""" Klasse für das Erstellen von Katzen """
Und zum Anlegen einer Instanz (sprich ein Objekt) hatten wir folgenden Aufruf:
Extrem gut sieht man die internen Auswirkungen des Codes bei der Nutzung des Live-Editor
(https://www.python-lernen.de/python-online-lern-editor.htm):
Wir haben die erste Instanz angelegt – unser erstes Objekt lebt.
Genau das wollen wir zum Testen für das Alter als Vorgabewert hinterlegen.
Hier kommt wieder unsere __init__() -Methode zum Tragen. Wir können Eigenschaften mit
Vorgabewert erweitern. Das kann man, muss aber nicht. Im Beispiel machen wir es nur für die
Eigenschaft „alter“:
Intern im Speicher ist nun beim Alter die 0 als Standard-Argument hinterlegt:
© https://www.python-lernen.de/oop-klasse-objekt-instanz-anlegen.htm Seite 288
Erstellen wir unsere Instanz (Objekt) mit einer Angabe vom Alter, wird dieses genommen. Diese
Angabe hat immer Vorrang.
Tragen wir allerdings beim Initialisieren nichts ein, dann kommt der Vorgabewert zum Zug. So
könnten wir auch noch festlegen, dass die meisten Katzen schwarz sind (das weiß man doch,
wenn man dem Sprichwort glaub).
Erstellen wir nun ein neues Objekt „katze_karlo“ nur mit seinem Rufnamen, erhält dieser die
Vorgabewerte zugewiesen:
Und natürlich sind genau deshalb in dieser Sekunde irgendwo auf der Welt (und natürlich in
Ihrem Computer) zwei Katzen entstanden. „High five“ sage ich da nur!
© https://www.python-lernen.de/oop-klasse-objekt-instanz-anlegen.htm Seite 289
Haben wir beispielsweise nur die Farbe als Vorgabewert und nicht das Alter, kommt eine
Fehlermeldung. Folgender Code geht schief!
Als Fehlermeldung erhalten wir dann: „SyntaxError: non-default argument follows default
argument“
© https://www.python-lernen.de/klassen-methoden-erstellen-und-aufrufen.htm Seite 290
Bei der Festlegung, welche Methoden für unsere BauplanKatzenKlasse hatten wir notiert:
Eigenschaften:
Farbe
Alter
Rufname
Methoden:
miauen
schlafen
fressen
schmusen
Also integrieren wir als Methode „miauen“. Eigentlich müssten wir für die Lautsprache von
Katzen 10 weitere unterschiedliche Lautarten als Methode integrieren (man sollte seiner Katze
mal genauer zuhören – im Gegensatz zum Hund, der nur 10 kann, kann die Katze bis 100
Einzellaute). Aber wir wollen nicht übertreiben. Unsere digitale Katze darf nur „miauen“ als
Methode.
class BauplanKatzenKlasse():
""" Klasse für das Erstellen von Katzen """
Wir bauen einen weiteren Bereich (Einrückung nicht vergessen!) mit def tut_miauen() ein.
Auch hier ist extrem wichtig, dass „self“ als erstes Argument nicht zu vergessen! Sonst erhält
man die Fehlermeldung „TypeError: tut_miauen() takes 0 positional arguments but 1 was
given“
© https://www.python-lernen.de/klassen-methoden-erstellen-und-aufrufen.htm Seite 291
class BauplanKatzenKlasse():
""" Klasse für das Erstellen von Katzen """
def tut_miauen(self):
print("miau")
Um nun die Methode „tut_miauen()“ zu nutzen, wird nach dem Erzeugen des Objektes diese mit
Objektnamen und Methode (verknüpft mit einem Punkt) und danach Klammern aufgerufen:
class BauplanKatzenKlasse():
""" Klasse für das Erstellen von Katzen """
def tut_miauen(self):
print("miau")
miau
Rufen wir nun die Methode auf, können wir die Anzahl übergeben:
katze_sammy.tut_miauen(3)
Das ist dasselbe, wie wir schon bei der Methode „tut_miauen“ programmiert haben. Wir
machen noch eine Textausgabe, wie lange geschlafen wird:
Interessant wäre doch, wie lange die Katze insgesamt über den Tag weg schläft?
Jetzt müssen wir unsere Methode tut_schlafen() noch entsprechend erweitern. Auf den
Wert der Eigenschaft „schlafdauer“ können wir einfach über das self.schlafdauer
zugreifen und diesen Wert entsprechend erhöhen. Danach lassen wir uns die bisherige
Gesamtdauer ausgeben
class BauplanKatzenKlasse():
""" Klasse für das Erstellen von Katzen """
Starten Sie in der Konsole das Programm mit dem Parameter „-i“ – die exakte Beschreibung
von dem Trick gibt es im Kapitel www.python-lernen.de/trick-programm-ausfuehren-und-in-
konsole-debuggen.htm
python -i BauplanKatzenKlasse.py
Im Folgenden sieht man die Möglichkeiten – erster Schritt: Das bestehende Programm wird
abgearbeitet und gibt folgende Ausgaben.
>>>
Jetzt können wir „katze_sammy“ miauen lassen – dazu geben wir einfach nach den 3
Größerzeichen den Funktionsaufruf ein:
© https://www.python-lernen.de/klassen-methoden-erstellen-und-aufrufen.htm Seite 294
>>> katze_sammy.tut_miauen(5)
>>>
>>> katze_sammy.tut_miauen(5)
>>> katze_sammy.tut_schlafen(10)
>>>
Wir können auch neue Objekte anlegen! Erwecken wir eine neue Katze zum Leben über:
Als Rückmeldung kommt nichts, da beim Anlegen einer neuen Instanz (Objektes) dies nicht
von unserem Programm kommentiert wird:
© https://www.python-lernen.de/klassen-methoden-erstellen-und-aufrufen.htm Seite 295
>>> katze_sammy.tut_miauen(5)
>>> katze_sammy.tut_schlafen(10)
>>>
Auch „katze_soni“ darf schlafen – hier sieht man, dass die Schlafdauer für alle Katzen getrennt
aufaddiert wird:
Unbedingt testen – diese Möglichkeit macht richtig Spaß und so kann man auch hartnäckige
Fehler einfacher finden.
parken
Kilometerstand ausgeben
Viel Spaß beim Umsetzen. Unser bisheriger Programmcode als Beispiellösung, an dem
weitergearbeitet werden kann:
class Pkw():
""" Klasse für das Erstellen von Personenkraftwagen """
class Pkw():
""" Klasse für das Erstellen von Personenkraftwagen """
def hupen(self):
""" hier sollte noch eine MP3-Datei ausgegeben werden """
print("Trööt")
def parken(self):
""" neben fahren schon das größere Problem in Städten """
print("Ich habe eine Parkplatz gefunden")
def kilometerstand(self):
""" Ausgabe des KM-Standes vom Tacho """
print("Ich habe ", str(self.kmstand) ," auf dem Tacho")
Jetzt können wir uns die Hilfe-Funktion zu dieser Klasse ausgeben lassen und erhalten die von
uns eingegebene Erklärung zur Klasse und Methoden:
….
trabi.kilometerstand()
trabi.parken()
print(help(Pkw))
class Pkw(builtins.object)
| Pkw(farbe, baujahr, kmstand, sitze, marke)
|
| Klasse für das Erstellen von Personenkraftwagen
|
| Methods defined here:
|
| __init__(self, farbe, baujahr, kmstand, sitze, marke)
| Eigenschaften farbe, baujahr, kmstand, Sitzplätze, Marke erfassen
|
| fahren(self, km)
| weiviel KM gefahren werden, was dem Tachostand aufaddiert wird
|
| hupen(self)
| hier sollte noch eine MP3-Datei ausgegeben werden
|
| kilometerstand(self)
| Ausgabe des KM-Standes vom Tacho
|
| parken(self)
| neben fahren schon das größere Problem in Städten
|
| ----------------------------------------------------------------------
| Data descriptors defined here:
|
| __dict__
| dictionary for instance variables (if defined)
|
| __weakref__
| list of weak references to the object (if defined)
Zusätzlich können wir uns noch die enthaltenen Methoden der Klasse und des erzeugten
Objekts anzeigen lassen über die Python-Anweisung dir() . Auch das packen wir ans Ende
dazu:
….
trabi.kilometerstand()
trabi.parken()
print(help(Pkw))
print(dir(Pkw))
print(dir(trabi))
Es sind alle von uns definierten Methoden von fahren, hupen bis parken aufgeführt.
Schauen wir uns die Ausgabe von dem Objekt mit dir(trabi) an, dann haben wir zusätzlich
neben den Methoden auch die Eigenschaften aufgeführt:
Bleiben wir bei unserem Beispiel mit Katzen. Bisher hatte unsere Klasse Katzen folgenden
Aufbau:
Klasse
Eigenschaften:
Farbe
Alter
Rufname
Methoden:
miauen
schlafen
fressen
schmusen
Jetzt wollen wir den Überbegriff zur Katze: Es handelt sich um ein Tier und genauer um ein
Säugetier (was man als Mensch auch manchmal beim Milchtritt der Katze direkt abbekommt).
Um das Beispiel besser ausbauen zu können, nehmen wir noch die Konkurrenz zur Katze dazu,
also Hunde. Wir haben also für beide den Überbegriff Säugetier – unsere neue „Über“-Klasse,
die es zu beerben gilt!
© https://www.python-lernen.de/vererbung-python.htm Seite 301
Und nun können die Eigenschaften der Katze in die Klasse Säugetier umgebaut werden. Die
Oberklasse Säugetier bekommt nun Eigenschaften der Unterklasse Katze, damit auch etwas
vererbt werden kann. In der Unterklasse Katze werden die übernommenen Eigenschaften
entfernt und somit haben wir eine sehr aufgeräumte Klasse was den Code sehr gut lesbar
macht.
Oberklasse bekommt Eigenschaften der Unterklasse, damit auch etwas vererbt werden kann.
© https://www.python-lernen.de/vererbung-python.htm Seite 302
class BauplanKatzenKlasse():
""" Klasse für das Erstellen von Katzen """
Jetzt erstellen wir unsere allgemeine Klasse „Tier“, die alle Eigenschaften der Katze erhält, was
die Klasse der Katze bereinigt (doppelt ist unnötig):
class Tier():
""" Klasse für das Erstellen von Säugetieren """
class BauplanKatzenKlasse():
""" Klasse für das Erstellen von Katzen """
Nach dem Starten des Python-Programms erhalten wir allerdings eine Fehlermeldung, dass
unsere Katzen-Klasse keinen Konstruktor hat, der das Argument übernehmen könnte.
Bisher gibt es auch noch keine Verbindung zwischen den beiden Klassen. Schaffen wir die
Verbindung!
class BauplanKatzenKlasse(Tier):
Die __init__ -Methode wird weiterhin benötigt! Allerdings wird bei der erbenden Klasse
innerhalb von __init__ die Eigenschaften über super() aus der Eltern-Klasse (also die Klasse
von der man erbt) „abgeholt“:
Dieses erst einmal ominöse super() steht für „superclass“, sprich Oberklasse. Wir stellen
damit eine Verbindung zwischen der Eltern-Klasse (Klasse, von der Kind erbt) und Kind-Klasse
her.
© https://www.python-lernen.de/vererbung-python.htm Seite 303
Unsere Katzen-Klasse ist schlanker geworden, wobei wir noch keinen Code gespart haben, da
der bisherige Code in die neue Klasse „Tier“ gewandert ist. Hier der bisher erstellte Code
komplett:
class Tier():
""" Klasse für das Erstellen von Säugetieren """
class BauplanKatzenKlasse(Tier):
""" Klasse für das Erstellen von Katzen """
Legen wir nun eine weitere Kind-Klasse (also noch eine Klasse, die von der Eltern-Klasse erbt)
an, sieht man die Ersparnisse deutlich. Und der Code ist übersichtlicher! Bauen wir eine Klasse
Hund. Nachdem wir nun schon mit Klassen umgehen können und den sperrigen Namen
„BauplanKatzenKlasse“ nicht wirklich schön ist, bekommt unsere Hunde-Klasse einen
schöneren Namen, und zwar „Hund“. Zur Erinnerung: erkennbar ist die Klasse immer an der
Schreibweise vom ersten Buchstaben in Großschreibung. Wir legen uns auch gleich ein neues
Objekt „hund_bello“ zum Testen an, zum Testen, ob das alles funktioniert.
© https://www.python-lernen.de/vererbung-python.htm Seite 304
class Tier():
""" Klasse für das Erstellen von Säugetieren """
class BauplanKatzenKlasse(Tier):
""" Klasse für das Erstellen von Katzen """
class Hund(Tier):
""" Klasse für das Erstellen von Hunden """
Unsere Klasse Tier wird nun über die Methode „tut_schlafen()“ erweitert.
class Tier():
""" Klasse für das Erstellen von Säugetieren """
Weder bei unserer Katzen-Klasse noch bei der Hund-Klasse müssen wir irgendetwas machen.
Beide erben automatisch alle Methoden der Eltern-Klasse „Tier“, die sofort zur Verfügung
stehen. Das können wir auch gleich testen über:
hund_bello.tut_schlafen(4)
katze_sammy.tut_schlafen(5)
hund_bello.tut_schlafen(2)
Der Hund schläft öfters, dass man schön sieht, dass für jede Instanz (also Bello und Sammy
getrennt voneinander) automatisch ein Schlafkonto geführt wird:
hund_bello.tut_schlafen(4)
katze_sammy.tut_schlafen(5)
hund_bello.tut_schlafen(2)
class Tier():
""" Klasse für das Erstellen von Säugetieren """
class BauplanKatzenKlasse(Tier):
""" Klasse für das Erstellen von Katzen """
class Hund(Tier):
""" Klasse für das Erstellen von Hunden """
katze_sammy.tut_reden(1)
hund_bello.tut_reden(3)
© https://www.python-lernen.de/attribute-und-methoden-ueberschreiben.htm Seite 307
Aber was ist mit Methoden, die so nicht passen? Unsere Methode „tut_miauen()“ mag ja noch
für die Katze passen, ist aber beim Hund merkwürdig. Also bekommt die Elternklasse die
Methode „tut_reden()“ (sorry, ein besserer Methodenname fällt mir gerade nicht ein). Bei der
„Rede“ kommt noch als Ausgabe, wer da gerade redet:
Wir erhalten:
class Tier():
""" Klasse für das Erstellen von Säugetieren """
class BauplanKatzenKlasse(Tier):
""" Klasse für das Erstellen von Katzen """
class Hund(Tier):
""" Klasse für das Erstellen von Hunden """
katze_sammy.tut_reden(1)
hund_bello.tut_reden(3)
Das ist natürlich für den Hund frustrierend und führt langfristig zu Hundedepressionen. Dem
wollen wir vorbeugen.
Also erzeugen wir in der Hund-Klasse eine Methode mit dem exakt gleichen Namen! Somit wird
diese bei Aufruf ausgeführt und somit überschreibt diese die Methode der Elternklasse:
Unsere Hundeklasse:
class Hund(Tier):
""" Klasse für das Erstellen von Hunden """
Wird nun eine Unterhaltung zwischen Hund und Katze gehalten, läuft diese wie gewohnt ab:
katze_sammy.tut_reden(1)
hund_bello.tut_reden(3)
class Tier():
""" Klasse für das Erstellen von Säugetieren """
class BauplanKatzenKlasse(Tier):
""" Klasse für das Erstellen von Katzen """
class Hund(Tier):
""" Klasse für das Erstellen von Hunden """
katze_sammy.tut_reden(1)
hund_bello.tut_reden(3)
Beim Lkw soll die Methode „parken()“ überschrieben werden. Es soll als Ausgabe kommen „auf
Firmenhof abgestellt“.
© https://www.python-lernen.de/attribute-und-methoden-ueberschreiben.htm Seite 311
Unser bisheriger Code aus der letzten Lösung, der jetzt erweitert werden soll.
class Pkw():
""" Klasse für das Erstellen von Personenkraftwagen """
def hupen(self):
""" hier sollte noch eine MP3-Datei ausgegeben werden """
print("Trööt")
def parken(self):
""" neben fahren schon das größere Problem in Städten """
print("Ich habe eine Parkplatz gefunden")
def kilometerstand(self):
""" Ausgabe des KM-Standes vom Tacho """
print("Ich habe ", str(self.kmstand) ," auf dem Tacho")
Methode „parken()“ beim Lkw überschrieben mit Ausgabe: „auf Firmenhof abgestellt“.
Sortieren wir die Punkte, in welcher Reihenfolge diese am meisten Sinn ergeben:
class Fahrzeug():
""" Klasse für das Erstellen von Fahrzeugen """
class Pkw(Fahrzeug):
""" Klasse für das Erstellen von Personenkraftwagen """
Der gesamte Code (auch zum Testen, denn an der Ausgabe hat sich nichts geändert – aber
funktionieren sollte es)
© https://www.python-lernen.de/loesung-klassen-vererbung.htm Seite 313
class Fahrzeug():
""" Klasse für das Erstellen von Fahrzeugen """
def hupen(self):
""" hier sollte noch eine MP3-Datei ausgegeben werden """
print("Trööt")
def parken(self):
""" neben fahren schon das größere Problem in Städten """
print("Ich habe eine Parkplatz gefunden")
def kilometerstand(self):
""" Ausgabe des KM-Standes vom Tacho """
print("Ich habe ", str(self.kmstand) ," auf dem Tacho")
class Pkw(Fahrzeug):
""" Klasse für das Erstellen von Personenkraftwagen """
Und nun noch in Eigenschaft ( self nicht vergessen) speichern, damit wir darauf zugreifen
können:
class Pkw(Fahrzeug):
""" Klasse für das Erstellen von Personenkraftwagen """
Eine von der Elternklasse unabhängige Eigenschaft. Auch andere Geschwisterklassen wissen
von der Eigenschaft nichts, denn diese erben nur von der Elternklasse!
class Lkw(Fahrzeug):
""" Klasse für das Erstellen von Lastkraftwagen """
class Lkw(Fahrzeug):
""" Klasse für das Erstellen von Lastkraftwagen """
def parken(self):
print("auf Firmenhof abgestellt")
class Lkw(Fahrzeug):
""" Klasse für das Erstellen von Lastkraftwagen """
def parken(self):
print("auf Firmenhof abgestellt")
def aufladen(self):
print("habe fertig geladen")
class Fahrzeug():
""" Klasse für das Erstellen von Fahrzeugen """
def hupen(self):
""" hier sollte noch eine MP3-Datei ausgegeben werden """
print("Trööt")
self.kmstand += km
print("Ich fahre ", km, " Kilometer")
print("Insgesamt bin ich ", self.kmstand ," gefahren")
def parken(self):
""" neben fahren schon das größere Problem in Städten """
print("Ich habe eine Parkplatz gefunden")
def kilometerstand(self):
""" Ausgabe des KM-Standes vom Tacho """
print("Ich habe ", str(self.kmstand) ," auf dem Tacho")
class Pkw(Fahrzeug):
""" Klasse für das Erstellen von Personenkraftwagen """
class Lkw(Fahrzeug):
""" Klasse für das Erstellen von Lastkraftwagen """
def parken(self):
print("auf Firmenhof abgestellt")
def aufladen(self):
print("habe fertig geladen")
Der große Vorteil von objektorientierter Programmierung haben wir am Anfang vom Kapitel
gesehen, dass wir benötigte Datenstrukturen passend zu unserem Objekt (was Realität
abbildet) zusammenbauen können.
Einen Schritt zurück. Schauen wir uns den Datentyp Liste an.
Über die Anweisung dir() sehen wir die verfügbaren Methoden (es handelt sich bei Listen
auch im Objekte, was man auch in der Anwendung sieht).
Wir können zum Beispiel die Daten der Liste auslesen über die Methode pop() :
Die Anweisung pop() liest das letzte Element aus und wirft es aus der Liste:
Kai
Schauen wir uns eine Klasse an mit einer ähnlichen Datenstruktur. Wir basteln uns einen
sportiven Jogger, der durch die Welt läuft und gelaufene Zeiten sammelt. Hier haben wir in
unserer Klasse eine Liste mit dem Namen gelaufene_zeiten und einer Methode
zeiterfassung() .
© https://www.python-lernen.de/oop-vererbung-weiterdenken.htm Seite 318
class Jogger():
""" sportliche Klasse für das Verwalten von gelaufenen Zeiten """
Wir sehen bei der __init__ , dass unsere übergebene Zeit eine Liste ist (die eckigen
Klammern verraten dies).
class Jogger():
""" sportliche Klasse für das Verwalten von gelaufenen Zeiten """
Laeufer_Hans = Jogger("M40")
print(Laeufer_Hans.altersklasse)
Laeufer_Hans.zeiterfassen(["2:30"])
print(Laeufer_Hans.gelaufene_zeiten)
Laeufer_Hans.zeiterfassen(["2:40", "3:10"])
print(Laeufer_Hans.gelaufene_zeiten)
Als Ergebnis sehen wir die Altersklasse (das ist das Teil, damit Läufer sich untereinander
vergleichen können – sprich unser Läufer ist zwischen 40 und 50 Jahre alt. Und seine
gesammelten Zeiten:
M40
['2:30']
['2:30', '2:40', '3:10']
Lassen wir uns über dir() ausgeben, was so an Methoden und Eigenschaften unsere Klasse
und unser Objekt hat:
print(dir(Jogger))
print(dir(Laeufer_Hans))
Wenn wir nun für die Eigenschaft „gelaufene_zeiten“ Methoden wie es die Datenstruktur „Liste“
anbietet gerne anwenden würden, müssten wir selber neue Methoden schreiben. Aber Faulheit
siegt (zumindest, wenn man irgendwann auch mal Feierabend haben möchte).
class Jogger(list):
Lassen wir uns jetzt wieder die Möglichkeiten des Objekts über dir() ausgeben:
print(dir(Jogger))
Jetzt stehen uns neben „zeiterfassung()“ auch alle Methoden von „list” zur Verfügung:
class Jogger(list):
""" sportliche Klasse für das Verwalten von gelaufenen Zeiten """
Laeufer_Hans = Jogger("M40")
Laeufer_Hans.zeiterfassen(["2:30"])
Laeufer_Hans.zeiterfassen(["2:40", "3:10"])
# print(dir(Jogger))
print()
print("vor POP:")
print(Laeufer_Hans.gelaufene_zeiten)
print("POP:")
print(Laeufer_Hans.gelaufene_zeiten.pop())
print("nach POP:")
print(Laeufer_Hans.gelaufene_zeiten)
Und als Ergebnis erhalten wir wie erwartet nach der allgemeinen Methode pop() , die uns das
Objekt „Liste“ zur Verfügung stellt:
vor POP:
POP:
3:10
nach POP:
['2:30', '2:40']
Am Rande: die Methode pop() würde auch so in der Klasse zu Verfügung stehen :). Hier
sieht man auf jeden Fall, wie weit Klassen erben können und ich denke, das Wissen darum
kann sehr hilfreich sein.
© https://www.python-lernen.de/oop-unterschied-eigenschaften-und-variablen.htm Seite 321
Unsere Oberklasse „Tier“ bekommt eine Variable gleich nach der Anlage der Klasse:
class Tier():
""" Beispiel für Variablen in Klassen """
tieranzahl = 0
def anzahl_tiere(self):
print(" aktuelle Anzahl: ", Tier.tieranzahl)
Zusätzlich können wir und die Anzahl der Tiere über die Methode anzahl_tiere()
ausgeben lassen.
Unsere Kindklassen „Katze“ und „Hund“ greifen auf die Variable gleich am Anfang zu und
lassen diese ausgeben:
class Tier():
""" Beispiel für Variablen in Klassen """
tieranzahl = 0
def anzahl_tiere():
print("aktuelle Anzahl: ", Tier.tieranzahl)
class Katze(Tier):
""" Klasse für das Erstellen von Katzen """
print("Aus Klasse Katze: ", Tier.tieranzahl)
class Hund(Tier):
""" Klasse für das Erstellen von Hunden """
print("Aus Klasse Hund: ", Tier.tieranzahl)
Tier.anzahl_tiere()
aktuelle Anzahl: 0
Man sieht hier sehr schön, dass der „Kopfbereich“ der Klassen auf jeden Fall ausgeführt
werden. Somit erhalten wir sofort die Ausgabe „Aus Klasse Katze: 0“ und dasselbe beim Hund.
Erst dann rufen wir die Methode Tier.anzahl_tiere() auf.
print(Tier.tieranzahl)
Und natürlich können wir überall die Variable setzen (auch außerhalb der Klassen und die
Anzahl innerhalb der Klasse würde sich ändern!). Einfach einmal probieren.
Tier.anzahl_tiere()
print(Tier.tieranzahl)
Tier.tieranzahl = 5
Tier.anzahl_tiere()
Jedes Mal, wenn wir ein neues Objekt erstellen, wird die __init__ durchlaufen. Wenn wir
nun in beide (sowohl bei Hund wie Katze) dieses Variable erhöhen, können wir jederzeit die
Gesamtanzahl der aktuell erstellten Objekte (sprich wie viele Hunde und Katzen gibt es
insgesamt) abfragen:
class Katze(Tier):
""" Klasse für das Erstellen von Katzen """
print("Aus Klasse Katze: ", Tier.tieranzahl)
Und nun basteln wir Tiere – sprich wir erzeugen Objekte in Form von einer Katze und zwei
Hunden:
© https://www.python-lernen.de/oop-unterschied-eigenschaften-und-variablen.htm Seite 323
Tier.anzahl_tiere()
katze_schnurri = Katze("Schnurri")
print(katze_schnurri.rufname)
Tier.anzahl_tiere()
hund_bello = Hund("Bello")
print(hund_bello.rufname)
Tier.anzahl_tiere()
hund_wedler = Hund("Wedler")
print(hund_wedler.rufname)
Tier.anzahl_tiere()
aktuelle Anzahl: 0
Schnurri
aktuelle Anzahl: 1
Bello
aktuelle Anzahl: 2
Wedler
aktuelle Anzahl: 3
class Tier():
""" Beispiel für Variablen in Klassen """
tieranzahl = 0
def anzahl_tiere():
print("aktuelle Anzahl: ", Tier.tieranzahl)
class Katze(Tier):
""" Klasse für das Erstellen von Katzen """
# print("Aus Klasse Katze: ", Tier.tieranzahl)
class Hund(Tier):
""" Klasse für das Erstellen von Hunden """
# print("Aus Klasse Hunde: ", Tier.tieranzahl)
Tier.anzahl_tiere()
katze_schnurri = Katze("Schnurri")
print(katze_schnurri.rufname)
Tier.anzahl_tiere()
hund_bello = Hund("Bello")
print(hund_bello.rufname)
Tier.anzahl_tiere()
hund_wedler = Hund("Wedler")
print(hund_wedler.rufname)
Tier.anzahl_tiere()
© https://www.python-lernen.de/oop-eigenschaften-zugriff-absichern.htm Seite 325
Nehmen wir an, wir sind eine Bank (die fiktive Kontinentalbank) und verwalten Konten und Geld
für unsere Kunden.
Also brauchen wir eine Klasse, die sowohl Konten (mit einer Kontonummer) und aktuelles
Guthaben verwaltet.
class Konto:
""" unsere kleines Bankprogramm zum Verwalten Konten/Geld """
def kontostand_anzeigen(self):
print("aktueller Kontostand: ", self.kontostand)
kunde_schulz = Konto("000111555")
kunde_schulz.kontostand_anzeigen()
kunde_schulz = Konto("000111555")
kunde_schulz.kontostand_anzeigen()
kunde_schulz.geld_einzahlen(150)
kunde_schulz.kontostand_anzeigen()
Bei Banken und Buchführung gibt es immer doppelte Buchführung – es darf nichts nicht
nachvollziehbar sein. Wir realisieren dies in kleiner Form, in dem wir (wie im letzten Kapitel
schon gezeigt) eine Bestandszahl mitführen, wie viel Geld insgesamt gerade in der Bank sein
müsste und geben Einzahlungen, Auszahlungen und den Gesamtbestand aus:
© https://www.python-lernen.de/oop-eigenschaften-zugriff-absichern.htm Seite 326
class Konto:
""" unsere kleines Bankprogramm zum Verwalten Konten/Geld """
geldbestand = 0
def kontostand_anzeigen(self):
print("aktueller Kontostand: ", self.kontostand)
print("aktueller Geldbestand der Bank: ", Konto.geldbestand, "\n")
Wir lassen den Kunden Schulz 2-mal einzahlen und einmal abheben:
kunde_schulz = Konto("000111555")
kunde_schulz.kontostand_anzeigen()
kunde_schulz.geld_einzahlen(150)
kunde_schulz.kontostand_anzeigen()
kunde_schulz.geld_einzahlen(250)
kunde_schulz.kontostand_anzeigen()
kunde_schulz.geld_abheben(75)
kunde_schulz.kontostand_anzeigen()
aktueller Kontostand: 0
aktueller Geldbestand der Bank: 0
So weit, so gut. Die Rechnung passt: 150 + 250 -75 = 325 (was auch der aktuelle Geldbestand
der Bank zeigt).
© https://www.python-lernen.de/oop-eigenschaften-zugriff-absichern.htm Seite 327
Was passiert aber, wenn unser Kunde ein Schlitzohr ist? Er betätigt sich einfach eines direkten
Zugriffs. Vor dem letzten Abheben erhöht er einfach einmal sein Kontostand um 1000.
kunde_schulz = Konto("000111555")
kunde_schulz.kontostand_anzeigen()
kunde_schulz.geld_einzahlen(150)
kunde_schulz.kontostand_anzeigen()
kunde_schulz.geld_einzahlen(250)
kunde_schulz.kontostand_anzeigen()
kunde_schulz.kontostand += 1000
kunde_schulz.geld_abheben(75)
kunde_schulz.kontostand_anzeigen()
Und schon haben wir ein massives Problem – die Kontrollzahl weicht von dem Kontostand ab:
class Konto:
""" unsere kleines Bankprogramm zum Verwalten Konten/Geld """
geldbestand = 0
def kontostand_anzeigen(self):
print("aktueller Kontostand: ", self.kontostand)
print("aktueller Geldbestand der Bank: ", Konto.geldbestand, "\n")
kunde_schulz = Konto("000111555")
kunde_schulz.kontostand_anzeigen()
kunde_schulz.geld_einzahlen(150)
kunde_schulz.kontostand_anzeigen()
kunde_schulz.geld_einzahlen(250)
kunde_schulz.kontostand_anzeigen()
kunde_schulz.kontostand += 1000
kunde_schulz.geld_abheben(75)
kunde_schulz.kontostand_anzeigen()
Eigenschaften (und auch Variablen) dürfen nicht von außen veränderbar sein. Auch hier hilft
uns Python. Wir können die Sichtbarkeit von Eigenschaften und Variablen einschränken:
public standard, kann auch von Außerhalb der Klassen genutzt und geändert werden
Das bedeutet, dass wir unsere Eigenschaften und Variablen als privat auszeichnen müssen.
Weil wir ein sicherheitsbewusster Programmierer sind, werden alle verwendeten Eigenschaften
und Variablen als „privat“ mit den 2 Unterstrichen am Anfang gekennzeichnet.
© https://www.python-lernen.de/oop-eigenschaften-zugriff-absichern.htm Seite 329
class Konto:
""" unsere kleines Bankprogramm zum Verwalten Konten/Geld """
__geldbestand = 0
def kontostand_anzeigen(self):
print("aktueller Kontostand: ", self.__kontostand)
print("aktueller Geldbestand der Bank: ", Konto.__geldbestand, "\n")
Ab jetzt ist weder das direkte Abfragen von Variablen/Eigenschaften noch das Setzen von
Werten außerhalb der Klasse möglich. Ein Versuch endet mit einer Fehlermeldung:
kunde_schulz = Konto("000111555")
kunde_schulz.kontostand_anzeigen()
kunde_schulz.geld_einzahlen(150)
kunde_schulz.__kontostand += 1000
Bank gerettet!
Was passiert, wenn wir mit einer Kindklasse auf die geschützten Werte zugreifen wollen?
Diese ist für uns natürlich die ideale Übung als Kindeklasse eines normalen Kontos.
Auszahlen finden nur statt, wenn der gewählte Betrag nicht das Konto in das Minus treiben
würde.
Allerdings kommt nun als Erschwerung dazu, dass wir nicht mehr so einfach Zugriff auf alle
Werte und Eigenschaften der Klasse „Konto“ haben, da diese als „__privat“ gekennzeichnet
sind.
class Pluskonto(Konto):
""" ein Konto, dass nicht überzogen werden kann """
Jetzt wollen wir auf den Kontostand der Elternklasse „Konto“ zugreifen. Was bisher einfach
funktionierte, geht durch die __privat gesetzten Eigenschaften nicht mehr. Aber wir benötigen ja
nur den Wert um vergleichen zu können, ob das Konto ins Minus gehen würde und wollen
diesen nicht verändert.
Also programmieren wir uns eine Methode in der Elternklasse, die uns diesen Wert liefert:
class Konto:
""" unsere kleines Bankprogramm zum Verwalten Konten/Geld """
__geldbestand = 0
def kontostand_anzeigen(self):
print("aktueller Kontostand: ", self.__kontostand)
print("aktueller Geldbestand der Bank: ", Konto.__geldbestand, "\n")
def kontostand_aktuell(self):
return self.__kontostand
Die letzte Methode kontostand_aktuell(self) liefert uns den aktuellen Wert über
return zurück:
Auf diesen können wir in der Kindklasse „Pluskonto“ zugreifen und zum Vergleich heranziehen:
© https://www.python-lernen.de/oop-eigenschaften-zugriff-absichern.htm Seite 331
Wir können von der Kindklasse auf die Methoden der Elternklasse über
super().geld_abheben() zugreifen. Dies ergänzen wir innerhalb unserer if-Abfrage.
class Konto:
""" unsere kleines Bankprogramm zum Verwalten Konten/Geld """
__geldbestand = 0
def kontostand_anzeigen(self):
print("aktueller Kontostand: ", self.__kontostand)
print("aktueller Geldbestand der Bank: ", Konto.__geldbestand, "\n")
def kontostand_aktuell(self):
return self.__kontostand
class Pluskonto(Konto):
""" ein Konto, dass nicht überzogen werden kann """
kunde_minderjaehrig = Pluskonto("0000935")
kunde_minderjaehrig.kontostand_anzeigen()
kunde_minderjaehrig.geld_einzahlen(200)
kunde_minderjaehrig.geld_abheben(101)
kunde_minderjaehrig.kontostand_anzeigen()
Sicherheit benötigt also ein wenig mehr Arbeit – ist aber problemlos machbar, wenn man weiß
wie.
© https://www.python-lernen.de/oop-eigenschaften-zugriff-absichern.htm Seite 333
© https://www.python-lernen.de/oop-import-klassen-auslagern.htm Seite 334
Klassen auslagern
Unsere erstellten Klassen benötigen Platz und wenn alles sich in einer Datei befindet, wird es
unübersichtlich. Daher ist eine gute Vorgehensweise, die Klassen als Module auszulagern und
einfach zu importieren.
Aus dem Bank-Beispiel aus dem letzten Kapitel machen wir ein Modul. Der Modulname ist
„konto.py“. Die Benennung ist sehr wichtig, da wir beim Import die Datei in der Form from
konto import Konto ohne Dateiendung „.py“ angeben!
Der Inhalt der Datei „konto.py“ – vorneweg der DOCstring für die Hilfe nicht vergessen:
© https://www.python-lernen.de/oop-import-klassen-auslagern.htm Seite 335
""" Klasse Konto und Pluskonto zum verwalten, ein- und auszahlen von Bankkonten """
class Konto:
""" unsere kleines Bankprogramm zum Verwalten Konten/Geld """
__geldbestand = 0
def kontostand_anzeigen(self):
print("aktueller Kontostand: ", self.__kontostand)
print("aktueller Geldbestand der Bank: ", Konto.__geldbestand, "\n")
def kontostand_aktuell(self):
return self.__kontostand
class Pluskonto(Konto):
""" ein Konto, dass nicht überzogen werden kann """
# oder
from konto import Konto
# oder
from konto import Pluskonto
# oder
from konto import Konto, Pluskonto
# oder
import konto
Warum gibt es da so viel Auswahl? Wir haben in unserem Modus sowohl die Klasse „Konto“
wie die Klasse „Pluskonto“.
# funktioniert
kunde_minderjaehrig = Konto("0000935")
# FEHLERMELDUNG (und bricht dann ab, das Zugriff unten würde funktionieren
kunde_minderjaehrig = Konto("0000935")
# funktioniert
kunde_minderjaehrig = Pluskonto("0000935")
import konto
Über die Anweisung import konto laden wir das gesamte Modul, allerdings müssen wir mit
dem Aufruf „Modulname.klassenname“ auf die Klassen zugreifen!
© https://www.python-lernen.de/oop-import-klassen-auslagern.htm Seite 337
import konto
# bzw.
kunde_minderjaehrig = konto.Pluskonto("0000935")
# funktioniert
kunde_minderjaehrig = Konto("0000935")
# funktioniert
kunde_minderjaehrig = Pluskonto("0000935")
Macht man ungern um Namenskonflikte zu vermeiden und man sieht auch so nicht, welche
Klassen eigentlich genutzt werden. Daher besser gleich folgende Variante!
# funktioniert
kunde_minderjaehrig = Konto("0000935")
# funktioniert
kunde_minderjaehrig = Pluskonto("0000935")
kunde_schulz = Konto("000111555")
kunde_schulz.kontostand_anzeigen()
kunde_schulz.geld_einzahlen(400)
kunde_schulz.geld_abheben(150)
kunde_schulz.kontostand_anzeigen()
kunde_minderjaehrig = Pluskonto("0000935")
kunde_minderjaehrig.kontostand_anzeigen()
kunde_minderjaehrig.geld_einzahlen(200)
kunde_minderjaehrig.geld_abheben(101)
kunde_minderjaehrig.kontostand_anzeigen()
aktueller Kontostand: 0
aktueller Geldbestand der Bank: 0
aktueller Kontostand: 0
aktueller Geldbestand der Bank: 250
Wer nachrechnen will, das passt mit der doppelten Buchführung so :).
© https://www.python-lernen.de/python-datenbanksysteme.htm Seite 339
Wir trennen dadurch Daten von Programm und müssen uns nicht kümmern um:
Wir übergeben einfach unserer Datenbank unsere Daten und im Folgenden können wir dann
über unser Programm bestimmen, was mit den Daten passieren soll. Meistens möchte man
diese in irgendeiner Form auswerten oder einfach nur ausgeben. Wobei bei der Ausgabe gerne
eine Auswahl (Selektion) stattfindet, damit nur gerade benötigte Daten angezeigt werden.
Wir wollen einen Geburtstagswarner programmieren, der seine Daten in einer Datenbank
speichert. Dazu benötigen wir Vorname, Nachname und das Datum des Geburtstags. Wer mag,
kann noch Telefonnummer und E-Mail mit in die Daten aufnehmen. Im ersten Schritt müssen
die Daten über ein Formular eingegeben und gespeichert werden können.
Zusätzlich können die Daten ausgegeben werden mit der gewünschten Sortierreihenfolge, z.B.
nach dem Vornamen oder Nachnamen oder Geburtsdatum.
Und als Bonbon sollen immer die kommenden 3 Geburtstage beim Start des Programms
angezeigt werden. Wir haben hier also eine Selektion der Daten nach einem bestimmten
Kriterium und eine sortierte Ausgabe.
Und zu guter Letzt wollen wir auch wieder Daten ändern (Tippfehler kommen vor) und auch
löschen (manchen Menschen möchte man nicht mehr zum Geburtstag gratulieren) können.
Das zur Funktion. Was bietet uns Python zum Thema Datenbanken?
Verschiedene Datenbanksysteme
Mit Python können wir verschiedene Datenbanksysteme wie MySQL, SQLite, Oracle,
PostgreSQL und weitere Datenbanken nutzen.
Über ein Datenbanksystem kann man sehr einfach Daten verwalten. Dazu gehört:
Datensätze anlegen
Datensätze löschen
Daten ändern
Daten suchen
Daten sortieren
© https://www.python-lernen.de/python-datenbanksysteme.htm Seite 340
Im folgenden Kapitel wollen wir mit SQLite arbeiten. Diese Variante ist ein optimaler Einstieg in
das Thema Datenbanken. Die grundsätzliche Programmierung ist bei allen Datenbanken die
Gleiche. Der Vorteil bei SQLite ist, dass dieses bereits als Modul in Python vorhanden ist und
direkt als Datei bei dem Softwareprojekt eingebettet ist. Wer im Dateisystem nachsehen mag –
es ist eine „.db“ -Datei.
Der große Vorteil für den Einsteiger ist: Wir müssen keine Client-Server-Datenbank wie
beispielsweise bei MySQL installieren. So kann auch sehr einfach die Anwendung mit der
Datenbank und bereits erfasste Daten weitergegeben werden.
Vorname
Nachname
Geburtstag
Datensatz anlegen
anzeigen
ändern
löschen
suchen
sortieren
Dies setzen wir Schritt für Schritt in den folgenden Kapiteln um und lernen so den Umgang mit
Datenbanken in Python.
© https://www.python-lernen.de/sqlite-vorgehensweise.htm Seite 341
Wir starten mit SQLite, weil es uns gleich mehrere Vorteile bietet (wie in der einführenden
Beschreibung erwähnt). Es ist bereits in Python vorhanden und das Modul kann einfach
importiert werden. Die Daten selber werden in einer Datei mit der Dateiendung „.db“
gespeichert und können somit problemlos weitergegeben werden.
import sqlite3
Die folgenden 5 Schritte sind für die Interaktion mit Datenbanken meistens notwendig:
SQL-Query übergeben
commit: wir bestätigen der Datenbank, dass wir die SQL-Anweisung wirklich ausführen lassen
wollen
Schauen wir uns erst den Befehl an und dann kommt die Erklärung:
verbindung = sqlite3.connect("geburtstage.db")
Wir bauen also eine Verbindung (engl. „connection“ und das Verb verbinden „connect“) zu
unserer Datenbank „geburtstage.db“ auf. Gibt es diese Datenbank noch nicht, legt unser
Datenbanksystem „SQLite“ automatisch beim ersten Aufruf eine Datei im selben Ordner an.
Möchte man es nicht im gleichen Ordner wie die Python-Programme haben, dann einfach den
gewünschten Unterordner angeben (der Unterordner sollte bereits angelegt sein):
verbindung = sqlite3.connect("datenbank/geburtstage.db")
Ist der Ordner nicht angelegt, schlägt das Anlegen der Datenbank fehl und wir erhalten die
Fehlermeldung: „sqlite3.OperationalError: unable to open database file“
Also einfach Ordner im Betriebssystem anlegen, bevor wir unseren connect -Befehl darauf
loslassen!
© https://www.python-lernen.de/sqlite-vorgehensweise.htm Seite 342
import sqlite3
verbindung = sqlite3.connect("datenbank/geburtstage.db")
zeiger = verbindung.cursor()
Bisher haben wir eine Datenbank mit dem Namen „geburtstage.db“. Allerdings haben wir noch
keine Tabellen in der Datenbank. Grundsätzlich wäre der Aufbau unseres execute -Befehls:
zeiger.execute(SQL-Anweisung)
Eine Tabelle besteht wie in Excel aus Zeilen und Spalten. In Excel wird für die Spalten
automatisch die Benennung „A, B, C, … AA, AB“ verwendet. Das wäre für uns eher unpraktisch.
Im Unterschied zu Excel vergeben wir also für unsere Datenbank für jede Spalte:
die Feldlänge
Wir erzeugen (engl. „create“) eine Tabelle (engl. „table“) die einen Namen hat.
Gerne wird eine SQL-Anweisung auch als String vorbereitet und dann dieser String der
Anweisung execute übergeben. Das macht die SQL-Anweisung besser lesbar und somit
können sich Fehler nicht so einfach einschleichen. Also nochmals die gleiche Anweisung wie
oben:
© https://www.python-lernen.de/sqlite-vorgehensweise.htm Seite 343
sql_anweisung = """
CREATE TABLE personen (
vorname VARCHAR(20),
nachname VARCHAR(30),
geburtstag DATE
);"""
zeiger.execute(sql_anweisung)
import sqlite3
verbindung = sqlite3.connect("datenbank/geburtstage.db")
zeiger = verbindung.cursor()
sql_anweisung = """
CREATE TABLE personen (
vorname VARCHAR(20),
nachname VARCHAR(30),
geburtstag DATE
);"""
zeiger.execute(sql_anweisung)
verbindung.commit()
verbindung.close()
import sqlite3
verbindung = sqlite3.connect("datenbank/geburtstage.db")
zeiger = verbindung.cursor()
sql_anweisung = """
CREATE TABLE personen (
vorname VARCHAR(20),
nachname VARCHAR(30),
geburtstag DATE
);"""
zeiger.execute(sql_anweisung)
verbindung.commit()
verbindung.close()
Jetzt können wir unser Programm ausführen lassen und erhalten unsere Datenbank angelegt.
Auch wenn es noch keine Inhalte gibt, wird die Datei „geburtstage.db“ erzeugt und besitzt eine
Dateigröße (es steckt jetzt die vorbereitete Struktur darin).
Lassen wir den Code nochmals ausführen, bekommen wir eine Fehlermeldung:
Diesen Fehler können wir vermeiden, indem wir die SQL-Anweisung nur ausführen lassen, wenn
noch keine Tabelle existiert. Wir erweitern dazu unsere SQL-Anweisung um „IF NOT EXISTS”:
sql_anweisung = """
CREATE TABLE IF NOT EXISTS personen (
vorname VARCHAR(20),
nachname VARCHAR(30),
geburtstag DATE
);"""
© https://www.python-lernen.de/sqlite-insert-into-datensatz-speichern.htm Seite 345
Jetzt werden im nächsten Schritt die Daten (engl. „values“) übergeben – die Daten werden in
Klammern geschrieben:
Die Daten werden in der Reihenfolge eingegeben, wie wir die Felder festgelegt haben. Also in
unserem Beispiel: vorname, nachname, geburtstag
Wir wollen unseren „Johann Wolfgang von Goethe“ mit aufnehmen. Geboren wurde er am
28.8.1749.
So weit, so gut. In diesem Fall, nicht gut. Warum? Die Datenbank weiß nicht, was
zusammengehört: wo hört der Vorname auf und wo fängt der Nachname an. Daher werden
Daten, die zu einem Feld gehören, jeweils in Anführungszeichen gesetzt. Dabei nutzt man
sehr gerne einfache Anführungszeichen, da unsere SQL-Anweisung selber oft als String
erstellt wird.
Ob das nun passt oder nicht, sagt uns einfach die Reaktion der Datenbank. Also testen!
import sqlite3
verbindung = sqlite3.connect("datenbank/geburtstage.db")
zeiger = verbindung.cursor()
sql_anweisung = """
CREATE TABLE IF NOT EXISTS personen (
vorname VARCHAR(20),
nachname VARCHAR(30),
geburtstag DATE
);"""
zeiger.execute(sql_anweisung)
sql_anweisung = """
INSERT INTO personen VALUES ('Johann Wolfgang von', 'Goethe', '28.8.1749')
"""
zeiger.execute(sql_anweisung)
verbindung.commit()
verbindung.close()
Beim Ausführen bekommen wir keine Fehlermeldung. Scheint also geklappt zu haben.
Spannend wird es, wenn wir die Daten wieder auslesen. Wenn die Daten exakt so wieder
herauskommen, dann passt es. Oder doch nicht?
Wer auf die Auflösung der Anmerkung nicht warten kann, hier der Typ dazu. In SQLite
unterstützt die folgenden Datentypen: INTEGER, REAL, TEXT, BLOB und NULL. Wenn mir mit
DATE ums Eck kommen, kommt zwar keine Fehlermeldung aber effektiv wird es als TEXT
gespeichert! Gespeichert ist es, nur mit Datum „rechnen“ können wir erst nach irgendwelchen
Umwandlungsaktion über Python.
Bauen wir also unsere SQL-Anweisung über Variablen auf. Wir bleiben beim gleichen Beispiel
oben und ergänzen weitere bekannte Namen in unserer Datenbank, die man schon immer mal
gerne in seiner Adressliste gehabt hätte.
nachname = "Schiller"
vorname = "Friedrich"
geburtstag = "10.11.1759"
Und jetzt bauen wir eine SQL-Anweisung (die noch nicht optimal ist!):
Warum ist diese Vorgehensweise so nicht gut? Über solche Konstruktionen wird die
Datenbank anfällig für SQL-Injektions. Sprich von außen wird schadhafter Code eingebracht,
der dann unter Umständen direkt ausgeführt wird. Schlimmstenfalls könnte die komplette
© https://www.python-lernen.de/sqlite-insert-into-datensatz-speichern.htm Seite 347
Daher wollen wir die Daten nicht ungeprüft übergeben. Der folgende Aufbau filtert die
größten Probleme heraus:
Man sieht an der oberen Zeile, dass die SQL-Anweisung sehr lang werden kann und man
nach rechts scrollen muss. Das ist natürlich einerseits unpraktisch und andererseits
verbessert es nicht die Lesbarkeit. Abhilfe schafft die Technik der 3 Anführungszeichen
einsetzen. Somit hat Python kein Problem mehr, wenn wir unsere Anweisung in mehrere
Zeilen verteilen. Das macht besonders bei SQL-Anweisungen Sinn, da wir dann die Felder von
den Variablen besser getrennt darstellen können.
zeiger.execute("""
INSERT INTO personen
VALUES (?,?,?)
""",
(vorname, nachname, geburtstag)
)
import sqlite3
verbindung = sqlite3.connect("datenbank/geburtstage.db")
zeiger = verbindung.cursor()
nachname = "Schiller"
vorname = "Friedrich"
geburtstag = "10.11.1759"
zeiger.execute("""
INSERT INTO personen
VALUES (?,?,?)
""",
(vorname, nachname, geburtstag)
)
verbindung.commit()
verbindung.close()
Im folgenden Kapitel speichern wir mehrere Datensätze auf einen Rutsch – nicht nur einen
wie bisher.
© https://www.python-lernen.de/sqlite-insert-into-executemany.htm Seite 348
import sqlite3
verbindung = sqlite3.connect("datenbank/geburtstage.db")
zeiger = verbindung.cursor()
nachname = "Schiller"
vorname = "Friedrich"
geburtstag = "10.11.1759"
zeiger.execute("""
INSERT INTO personen
VALUES (?,?,?)
""",
(vorname, nachname, geburtstag)
)
verbindung.commit()
verbindung.close()
Wenn uns allerdings mehrere Daten vorliegen, dann möchten wir diese so effektiv wie möglich
in unserer Datenbank speichern können.
Als Erstes benötigen wir die Daten selber. Dazu bieten sich natürlich Listen an. Bisher haben
wir einzelne Variablen verwendet, was sehr schnell ab einer gewissen Menge an verschiedenen
Variablen sehr unübersichtlich wird. Daher nutzen wir eine Liste, in der wir in einer
vorgegebenen Reihenfolge unsere Namen und Geburtstagsdaten abspeichern:
Diese Liste kann jetzt einfach unsere SQL-Anweisung execute übergeben werden.
zeiger.execute("""
INSERT INTO personen
VALUES (?,?,?)
""", personendaten)
Was passiert aber, wenn wir eine geschachtelte Liste haben – sprich eine Liste mit vielen
Personendaten?
Wenn wir nun die geschachtelte Liste unserer SQL-Anweisung execute übergeben, erhalten
wir eine Fehlermeldung:
import sqlite3
verbindung = sqlite3.connect("datenbank/geburtstage.db")
zeiger = verbindung.cursor()
zeiger.executemany("""
INSERT INTO personen
VALUES (?,?,?)
""", beruehmtheiten)
verbindung.commit()
Es muss aber eine geschachtelte Liste sein. Diese kann aber auch nur einen Datensatz
enthalten wie im folgenden Beispiel:
Im folgenden Kapitel wollen wir auch mal schauen, was in unserer Datenbank angekommen
ist. Dazu lesen wir die Datenbank aus und zeigen die Inhalte an.
© https://www.python-lernen.de/sqlite-datenbank-auslesen.htm Seite 350
Und nun „holen“ wir die Daten ab und übergeben diese einer Liste. Am Rande bemerkt, das
englische Wort für holen bzw. abholen ist „fetch“. Mit den abgeholten in einer Liste
gespeicherten Daten können wir weiterarbeiten – in unserem Fall erst einmal ausgeben um
zu sehen, ob die in die Datenbank geschriebenen Daten auch wieder korrekt herauskommen.
inhalt = zeiger.fetchall()
print(inhalt)
import sqlite3
verbindung = sqlite3.connect("datenbank/geburtstage.db")
zeiger = verbindung.cursor()
zeiger.execute("SELECT * FROM personen")
inhalt = zeiger.fetchall()
print(inhalt)
verbindung.close()
[('Johann Wolfgang von', 'Goethe', '28.8.1749'), ('Johann Wolfgang von', 'Goethe', '28.8.1749'),
('Friedrich', 'Schiller', '10.11.1759')]
Wir haben also eine Liste mit unseren einzelnen Elementen. Unseren Goethe haben wir
versehentlich 2-mal in die Datenbank gespeichert. Interessanterweise scheint das
Geburtsdatum korrekt übernommen worden zu sein, obwohl wir dies in deutscher
Schreibweise gespeichert haben.
Möchte ich aus meiner Datenbank „personen“ nur noch den Nachnamen und den Geburtstag
erhalten, gebe ich nur diese beiden Feldnamen an:
© https://www.python-lernen.de/sqlite-datenbank-auslesen.htm Seite 351
import sqlite3
verbindung = sqlite3.connect("datenbank/geburtstage.db")
zeiger = verbindung.cursor()
zeiger.execute("SELECT nachname, geburtstag FROM personen")
inhalt = zeiger.fetchall()
print(inhalt)
verbindung.close()
Wir wollen unseren Datensatz von Herrn Schiller korrigieren. Schiller ist zwar primär mit dem
Vornamen Friedrich bekannt, aber seine kompletten Vornamen lauten: „Johann Christoph
Friedrich“
Also wollen wir unseren Datensatz aktualisieren. Schauen wir uns dazu erst die komplette SQL-
Anweisung an:
Die Anweisung UPDATE ist logisch: Aktualisiere (update) in der Tabelle „personen“ folgende
angegebene Daten. Bei den angegebenen Daten müssen wir nur die zu änderten Daten und das
entsprechende Feld über die SQL-Anweisung SET angeben.
In unserem Fall wollen wir unseren Herrn Schiller auswählen, also WHERE
nachname='Schiller' . Auf das Problem, dass es mehr als einen „Schiller“ in unserer
Tabelle gibt, kommen wir später noch zu sprechen.
Bauen wir unsere SQL-Anweisung um, damit wir wie gewohnt mit Variablen arbeiten können
und geschützt vor SQL-Injektionen sind.
nachname = "Schiller"
vorname = "Johann Christoph Friedrich"
Noch einmal, da es so wichtig ist! Hier ist die korrekte formulierte Bedingung in der SQL-
Anweisung mit WHERE extrem wichtig. Ansonsten bekommen ALLE Datensätze den neuen
Vornamen. Und das würde Goethe definitiv nicht gefallen.
Und einfach, weil es so schön ist, einmal diesen fatalen Fehler zu machen, lassen wir die
WHERE-Anweisung weg:
Anmerkung: das Komma nach (vorname, ) ist wichtig. Dazu später mehr.
© https://www.python-lernen.de/sqlite-update-datensatz-aendern.htm Seite 353
import sqlite3
verbindung = sqlite3.connect("datenbank/geburtstage.db")
zeiger = verbindung.cursor()
print(inhalt)
verbindung.close()
Lassen wir es aufführen. Falls eine Fehlermeldung kommt, bitte das Komma nach „('Goethe',)”
beachten.
Ungeschickterweise sind jetzt alle Goethes den Weg der Sterblichen gegangen. Wir haben
keinen einzigen mehr in der Datenbank.
Unsere SQL-Anweisung wurde exakt so ausgeführt, wie wir diese geschrieben haben. Lösche
alle Personen mit dem Nachnamen „Goethe“, egal wie oft diese Vorkommen und welchen
Vornamen diese haben. Wäre eine „Susanne Goethe“ in der Datenbank vorhanden gewesen,
wäre auch diese unserem Löschangriff zum Opfer gefallen.
Hier kommt nun ein grundsätzliches Problem in unserem Datenbankdesign zum Vorschein,
dass wir in den nächsten Kapiteln angehen müssen.
Bisher haben wir keine Möglichkeit exakt den einen Datensatz auszuwählen, den wir wollen.
Wir könnten zwar unsere WHERE -Bedingung noch weiter präzisieren mit Beispielsweise der
Angabe von weiteren Feldern:
Daher sind DELETE FROM außerordentlich gefährlich. Was passiert wohl bei der Anweisung:
Korrekt – alles wird gelöscht! Nur doof, wenn wir das eigentlich nicht wollten oder irgendwas
schieflief mit der WHERE -Bedingung!
Daher benötigen wir ein exaktes einmaliges Kriterium zum Löschen, damit exakt der eine
gewünschte Datensatz gelöscht werden kann.
Dafür brauchen wir zum Verständnis SQL-Grundlagen, die in den folgenden Kapiteln aufgebaut
werden.
© https://www.python-lernen.de/sql-grundlagen.htm Seite 356
Das Kürzel SQL stehen für „Structured Query Language“ – eine strukturierte Abfrage-Sprache.
Bevor wir ein Datenbanksystem nutzen können, müssen wir erst unsere Datenbank mit deren
Tabellen einrichten. Auf gut Deutsch: welche Felder gibt es und wie nennen wir diese, damit wir
komfortable wieder darauf zugreifen können. Wir definieren also unsere Daten bzw.
Datenfelder und können die gewünschte Struktur über eine SQL-Anweisung in der Datenbank
erzeugen. Ohne eine Datenbank und Daten können wir auch nicht die folgenden Bereiche
nutzen wie die Datenbank mit Daten zu füllen bzw. auszuwerten.
Auslesen der Datenbank auch mit bestimmten Bedingungen (man will ja nicht immer alle
Daten). Hier können auch mehrere Tabellen miteinander verknüpft werden und daraus das
Ergebnis ausgegeben werden.
© https://www.python-lernen.de/sql-grundlagen.htm Seite 358
ANSI-SQL
Hier der Begriff ANSI-SQL, damit man es mal gelesen hat und verorten kann. Das American
National Standards Institut (ANSI) hat festgelegte Standards. Diese gibt es auch für SQL.
Allerdings gibt es da über die Jahre mehrere verschiedene, da es bei SQL Verbesserungen und
Erweiterungen gegeben hat. Die verschiedenen SQL-Server bieten im Kern die gleiche Funktion,
die aber in der Nutzung leicht unterschiedlich sein kann, was hier am Anfang über das von uns
benötigte Wissen hinausgeht. Sollte man mal schlaflose Nächte haben, kann man sich mit den
verschiedenen ANSI-SQL-Varianten die Nacht vertreiben.
Lustig am Rande: MySQL – die ersten 2 Buchstaben vom Namen der Datenbank kommen von
dem Vornamen „My“. Diese ist die Tochter des MySQL-AB-Mitgründers Michael Widenius
(Monty genannt). Seine zweite Tochter heißt Maria (wurde auch als Namen für ein
Datenbanksystem verwendet: MariaSQL).
Die verschiedenen Datenbankserver orientieren sich alle am Standard der aktuellen SQL-
Version.
Schlüsselwörter:
einzelne SQL-Befehle
Anwendung:
nicht case-sensitiv (Groß- und Kleinschreibung macht keinen Unterschied), es gibt aber
Empfehlungen in Form von Schlüsselworten immer in Großbuchstaben, Rest in
Kleinschreibung bzw. gemischte Schreibweise.
© https://www.python-lernen.de/sql-grundlagen.htm Seite 359
Leerzeichen, Tabulatoren und Zeilenumbrüche dürfen nach Belieben genutzt werden. Hier ist
die bestmögliche Lesbarkeit das Ziel!
Zusätzlich wird auch für die meisten Datentypen eine Feldlänge vergeben.
Bezeichnung Datensatz: Die Zeilen in der Tabelle werden als Datensätze bezeichnet. Hier
haben wir dann alle Einzeldaten, die zu diesem Datensatz gehört. Bei einem Telefonbuch gäbe
es dann z.B. Vorname, Nachname, PLZ, Telefonnummer
Ein Datensatz ist eine Zusammenstellung von einzelnen Informationen, die sinnvoll
zusammengehören und daher schlecht getrennt werden können. In unserem Beispiel vom
Telefonbuch macht es Sinn, dass der Vorname und der Nachname in der gleichen Tabelle als
Datenfelder vorhanden sind.
Beziehungen in relationaler Datenbank: Schauen wir unser Beispiel mit der Telefonliste an.
Neben dem Vor- und Nachnamen speichern wir die Postleitzahl – aber keinen Ort! Warum? Hier
kommt der Vorteil von relationalen Datenbanken ins Spiel. Es geht um Beziehungen: Unser
Postleitzahlensystem in Deutschland hat zu jeder Postleitzahl genau einen Ort. Es macht also
wenig Sinn zusätzlich neben der PLZ den Ort in der Tabelle mit den Namen zu speichern. Für
die Orte können wir eine weitere Tabelle anlegen, in der nur Postleitzahl und zugehörige Orte
gespeichert werden. In dem Fall der neuen Tabelle ist unsere PLZ der Primärschlüssel unserer
Tabelle „ortsnamen“ (wir gehen jetzt einfach nur von Orten in Deutschland aus). Unser Feld
PLZ in der Tabelle „telefonbuch“ nennt sich auch „Fremdschlüssel“. Dieser Fremdschlüssel aus
der Tabelle „telefonbuch“ zeigt auf den Primärschlüssel „PLZ“ in der Tabelle „ortsnamen“.
[bild[Beispiel Datenbankdiagrammen]]
Den Primärschlüssel sieht man i.d.R. anhand eines Schlüsselsymbols und die Art der
Verknüpfung der Daten ist sofort sichtbar anhand einer Linie. Die Enden der Linien zeigen die
Art der Relation (Verknüpfung):
Schlüssel: Primärschlüssel
Referentielle Integrität (RI): die Referentielle Integrität dient zur Sicherstellung der
Datenintegrität zwischen den Tabellen. Durch die Verknüpfung von Fremdschlüssel und
Primärschlüssel kann das Datenbanksystem kontrollieren, ob ein Datensatz vorhanden ist und
der Fremdschlüssel verwendet werden darf. Auch ist es nicht einfach möglich den
Primärschlüssel zu verändern, wenn dieser als Fremdschlüssel bereits verwendet wird.
Es kann nur auf die formale Korrektheit kontrolliert werden – inhaltlich ist immer noch der
Nutzer in der Pflicht mitzudenken!
Schauen wir uns diese Grundlagen in konkreten Anwendungen an. Dann wird es auch greifbar.
Im folgenden Kapitel nutzen wir den Primärschlüssel für die eindeutige Auswahl eines
Datensatzes.
© https://www.python-lernen.de/sqlite3-shell.htm Seite 361
sqlite3
Jetzt können wir mit .help uns alle Befehle ansehen, die uns die sqlite3-Shell bietet.
Wir können alle Funktionen, die wir über den Umweg von Python kennengelernt haben auch
direkt in der SQLite3-Shell ausführen. Wollen wir unsere erstellte Datenbank „geburtstage.db“
nutzen, müssen wir diese laden. Da wir diese in einem Unterordner gespeichert haben, müssen
wir beim Pfad den Unterordner mit angeben:
.open datenbank/geburtstage.db
Bitte nicht wundern, wenn wir kein Feedback von der Shell bekommen:
.databases
sqlite> .databases
main: /Users/axel/Documents/Python-lernen.de/datenbank/geburtstage.db
Haben wir die erstellten Tabellen vergessen, erhalten wir über den Befehl .tables eine
Auflistung aller in der Datenbank vorhandenen Tabellen:
sqlite> .tables
adressen personen
Und jetzt können wir bereits direkt mit weiteren SQL-Anweisungen die Tabelle auslesen.
Lassen wir uns den Inhalt komplett anzeigen:
Um wieder die normalen Shell-Eingaben machen zu können, müssen wir das anschließende
Semikolon angeben!
sqlite> .quit
Axels-MBP:Python-lernen.de axel$
Über die Shell-Anweisung .show bekommen wir weitere Informationen über die Anzeige und
über die aktuell gewählte Datenbank:
sqlite> .show
echo: off
eqp: off
explain: auto
headers: on
mode: column
nullvalue: ""
output: stdout
colseparator: "|"
rowseparator: "\n"
stats: off
width:
filename: datenbank/geburtstage.db
sqlite>
Hier können wir nach Bedarf auch Änderungen durchführen. Beispielsweise können wir den
Trenner, der als Zeichen „|“ verwendet umstellen über die Anweisung .separator ^
Wir erhalten dann eine Textdatei, deren Datenfelder der Semikolons getrennt sind:
nachname;vorname;geburtstag
Müller;Mike;05.03.80
Sommer;Elke;02.05.87
Schuster;Johanna;10.10.93
Trister;Theodor;08.03.87
import csv
with open("adressen.csv") as csvdatei:
csv_reader_object = csv.reader(csvdatei, delimiter=';')
for row in csv_reader_object:
print(row)
Die ersten Zeichen 'ufeff' kommen daher, dass wir in der entsprechenden UTF8-Variante
abgespeichert haben. Da wir die Überschriften nicht benötigt, kann man diesen kleinen
Schönheitsfehler ignorieren und diese erste Zeile mit den Überschriften einfach mit einem
Texteditor aus der CSV-Datei löschen. Dann passt alles beim richtigen Import.
Jetzt wollen wir eine Verbindung zur Datenbank „adressen.db“ aufbauen und diese
gegebenenfalls neu anlegen, falls diese noch nicht existiert:
import csv
import sqlite3
verbindung = sqlite3.connect("adressen.db")
zeiger = verbindung.cursor()
sql_anweisung = """
CREATE TABLE IF NOT EXISTS adressen (
nachname VARCHAR(30),
vorname VARCHAR(20),
geburtstag DATE
);"""
zeiger.execute(sql_anweisung)
Ab jetzt können wir unsere SQLite3 Datenbank befüllen. Wir benötigen die entsprechende SQL-
Anweisung:
© https://www.python-lernen.de/sqlite3-datenbank-import-aus-csv-datei.htm Seite 366
import csv
import sqlite3
verbindung = sqlite3.connect("adressen.db")
zeiger = verbindung.cursor()
sql_anweisung = """
CREATE TABLE IF NOT EXISTS adressen (
nachname VARCHAR(30),
vorname VARCHAR(20),
geburtstag DATE
);"""
zeiger.execute(sql_anweisung)
sql_anweisung = """
INSERT INTO adressen (nachname, vorname, geburtstag)
VALUES (:nachname, :vorname, :geburtstag)
"""
Und zum Test können wir jetzt die Datenbank auslesen und den Inhalt anzeigen:
import sqlite3
verbindung = sqlite3.connect("adressen.db")
zeiger = verbindung.cursor()
zeiger.execute("SELECT * FROM adressen")
inhalt = zeiger.fetchall()
print(inhalt)
verbindung.close()
Wir haben alle Daten auf einen Rutsch in unsere SQLite3-Datenbank importiert und können
damit weiterarbeiten.
Bitmap-Grafiken anzeigen
Kollisionskontrolle
Sound abspielen
Pygame importieren/initialisieren
Da es sich um ein Modul handelt (muss auch erst installiert sein) muss dieses geladen und
initialisiert werden. Das können wir gleich am Anfang von unserem Python-Programm
erledigen:
Starten wir nun unser Programm und ist Pygame installiert, erhalten wir als Ausgabe:
pygame 1.9.6
Unser Programm macht noch nichts – wir erhalten nur in der Konsole eine kleine Rückmeldung
(aus der wir auch die Version der verwendeten Pygame-Library erfahren).
Sollte Pygame noch nicht installiert sein, dann erscheint eine Fehlermeldung. Dann bitte
Pygame installieren.
Farben nutzen
Was wäre ein Spiel ohne Farben? Um Farben nutzen zu können, müssen wir diese festlegen.
Hierbei hilft nicht, zu sagen, wir wollen „orange“ verwenden und gut ist. Nein – Farben werden
über die 3 Grundfarben Rot, Grün und Blau festgelegt. Daher auch die Bezeichnung RGB.
Dankbarweise fangen auf Englisch die 3 Grundfarben mit den gleichen Buchstaben an (red,
green, blue).
© https://www.python-lernen.de/pygame-tutorial.htm Seite 368
Zum Festlegen der Farben geben wir jeder dieser 3 Grundfarben einen Wert zwischen 0 und
255. Somit können wir über 16 Millionen verschiedener Farben nutzen. Geben wir dem ersten
Wert (der für Rot steht) die maximalen 255 und den zweiten und dritten Wert jeweils 0 erhalten
wir ein Rot.
Geben wir allen 3 Grundfarben der Werten 255 erhalten wir weiß.
Mischen wir die Werte lustig, erhalten wir eine der 16,7 Millionen möglichen Farben.
Es gibt zahlreiche Dienste Online, über die man die RGB-Werte herausbekommt (wie
beispielsweise https://www.webfx.com/web-design/color-picker/ ). Aber auch jedes
Bildbearbeitungsprogramm zeigt Farbwerte als RGB-Werte an (man muss nur wissen, wo man
suchen muss). Und darauf achten, dass wir dezimale Werte erhalten, ansonsten siehe weiter
unten bei hexadezimalen Werten.
Nachdem wir die gewünschte Farbe haben (unser Orange hat z.B. die Werte 255 bei Rot, 140
bei Grün und 0 bei Blau) können wir diese nutzen.
Hier als Beispiel (die Erklärung von screen.fill() folgt später noch ausführlich).
screen.fill((255,140,0))
Diese Schreibweise funktioniert zwar, aber macht wenig Spaß, da oft unklar ist, welche Farbe
damit gemeint ist. Daher nutzen wir einfach Konstanten. Wir legen also unsere Farben also
Konstante fest und nutzen dann den vergebenen Namen:
So können wir am Anfang von unserem Spiel alle genutzten Farben definieren und haben dann
einen übersichtlichen Code:
© https://www.python-lernen.de/pygame-tutorial.htm Seite 369
# genutzte Farbe
ORANGE = ( 255, 140, 0)
ROT = ( 255, 0, 0)
GRUEN = ( 0, 255, 0)
SCHWARZ = ( 0, 0, 0)
WEISS = ( 255, 255, 255)
Sollen die Farben in hexadezimaler Schreibweise genutzt werden, ist das in Python absolut
kein Problem. Hexadezimal zeichnet sich dadurch aus, dass unsere Zahlen nicht von 0 bis 9
gehen, sondern bis 16. Daher benötigen wir ab 9 dann entsprechende Codierung:
Dezimal Hexadezimal
8 8
9 9
10 A
11 B
12 C
13 D
14 E
15 F
Haben wir also den Maximalwert in Dezimal von 255 wird er als hexadezimale Zahl mit FF
angegeben.
Wollen wir hexadezimale Zahlen in Python nutzen, wird vorweg „0x“ angegeben. Also für FF
dann „0xFF“.
FF8C00
# genutzte Farbe
ORANGE = ( 0xFF, 0x8C, 0x00)
ROT = ( 0xFF, 0x00, 0x00)
Für die Nutzung ist es egal, ob man mit dezimalen oder hexadezimalen Zahlen arbeitet
# genutzte Farbe
ORANGE = ( 255, 140, 0)
ROT = ( 255, 0, 0)
GRUEN = ( 0, 255, 0)
SCHWARZ = ( 0, 0, 0)
WEiSS = ( 255, 255, 255)
# Fenster öffnen
pygame.display.set_mode((640, 480))
Lassen wir nun unser Programm ausführen, kommt für einen Sekundenbruchteil das Fenster
und verschwindet wieder. Logisch, da unser Programm ja sofort wieder beendet ist. Es hat
alles erledigt und räumt dann ordentlich wie Python ist das angezeigte Fenster wieder „auf“.
Vielleicht wundert man sich anfangs über set_mode . Von der Logik her würde man ja auf
irgendwas mit „open_window“ schließen. Das liegt daran, dass die pygame.display -
Anweisung deutlich mehr kann, außer ein Fenster zu erstellen.
Zusätzlich können wir unserem Fenster noch einen Titel verpassen, der dann später im
Fensterkopf angezeigt wird. Dazu nutzen wir wieder unsere Anweisung pygame.display mit
pygame.display.set_caption()
© https://www.python-lernen.de/pygame-tutorial.htm Seite 370
Störend ist natürlich, dass sich unser gezeichnetes Fenster sofort wieder schließt. Daher wird
es Zeit für Benutzeraktionen
Den Aufbau der Hauptroutine haben wir bereits in den vorherigen Kapiteln bei anderen Spielen
kennengelernt. Daher wird hier nicht nochmals darauf eingegangen. Unsere while -Schleife
läuft so lange, wie unsere Variable mit dem Namen „spielaktiv“ auf „True“ gesetzt ist. Sprich vor
der while-Schleife führen wir diese Variable ein.
Innerhalb der while -Schleife überprüfen wir, ob ein bestimmtes Ereignis (englisch „event“)
stattgefunden hat wie z.B. das Klicken auf den Exit-Button.
# genutzte Farbe
ORANGE = ( 255, 140, 0)
ROT = ( 255, 0, 0)
GRUEN = ( 0, 255, 0)
SCHWARZ = ( 0, 0, 0)
WEiSS = ( 255, 255, 255)
# Fenster öffnen
pygame.display.set_mode((640, 480))
# Schleife Hauptprogramm
while spielaktiv:
for event in pygame.event.get():
if event.type == pygame.QUIT:
spielaktiv = False
Wichtig ist diese grundlegende Logik. Wer diese verletzt, kann in unnötige Probleme laufen. Wir
haben in der Hauptschleife 5 Blöcke. Diese sollten auch nicht bunt gemischt werden.
Fenster löschen
Dies sieht in unserem Programm wie folgt aus. Es wurden Platzhalter in Form von
Anmerkungen eingebaut:
© https://www.python-lernen.de/pygame-tutorial.htm Seite 371
# Schleife Hauptprogramm
while spielaktiv:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
if event.type == pygame.QUIT:
spielaktiv = False
# Fenster aktualisieren
# Refresh-Zeiten festlegen
Bei den Refresh-Zeiten wird die Häufigkeit der Fenster-Aktualisierung festgelegt. Diese darf
weder zu häufig (bremst den Computer herunter) noch zu selten (Figuren bewegen sich
merkwürdig) stattfinden.
Vor dem Zeichnen des Spielfelds und der Spielfigur(en) wird das Fenster gelöscht. Dazu
zeichnen wir einfach den kompletten Bereich in der Grundfarbe. Hat unser Spiel die
Hintergrundfarbe Weiß, dann wäre unser Aufruf:
screen.fill(WEISS)
Unsere Farbe in der Konstanten WEISS haben wir am Anfang definiert. Zur Erinnerung: WEISS
= ( 255, 255, 255) .
Wichtig ist noch, dass der Zugriff auf screen eingerichtet wurde. Dazu wird beim „Fenster
öffnen“ dieser Zugriff festgelegt über:
# Fenster öffnen
screen = pygame.display.set_mode((640, 480))
pygame.display.flip()
Bei folgendem Code stellen wir 60 fps (frames per second = Bilder pro Sekunde) ein:
Wollen wir nur 10 Aktualisierungen pro Sekunden, dann ist die Angabe clock.tick(10)
# Schleife Hauptprogramm
while spielaktiv:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
if event.type == pygame.QUIT:
spielaktiv = False
print("Spieler hat Quit-Button angeklickt")
# Spielfeld löschen
screen.fill(WEISS)
# Spielfeld/figuren zeichnen
# Fenster aktualisieren
pygame.display.flip()
# Refresh-Zeiten festlegen
clock.tick(60)
pygame.quit()
# Schleife Hauptprogramm
while spielaktiv:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
if event.type == pygame.QUIT:
spielaktiv = False
print("Spieler hat Quit-Button angeklickt")
elif event.type == pygame.KEYDOWN:
print("Spieler hat Taste gedrückt")
Genauso können wir einen Klick mit der Maus abfragen über event.type ==
pygame.MOUSEBUTTONDOWN
# Schleife Hauptprogramm
while spielaktiv:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
if event.type == pygame.QUIT:
spielaktiv = False
print("Spieler hat Quit-Button angeklickt")
elif event.type == pygame.KEYDOWN:
print("Spieler hat Taste gedrückt")
elif event.type == pygame.MOUSEBUTTONDOWN:
print("Spieler hast Maus angeklickt")
Und für die meisten Spiele benötigen wir als Steuerung die Pfeiltasten auf der Tastatur. Diese
werden über folgende Bezeichnungen angesprochen
K_LEFT
K_RIGHT
K_UP
K_DOWN
K_SPACE
Hier kommt nun die Besonderheit, dass wir nur dann in die Auswertung gehen, wenn im
Allgemeinen eine Taste genutzt wird (und zwar beim Herunterdrücken). Wir verschachteln also
eine if-Abfrage in den Bereich elif event.type == pygame.KEYDOWN:
# Schleife Hauptprogramm
while spielaktiv:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
if event.type == pygame.QUIT:
spielaktiv = False
print("Spieler hat Quit-Button angeklickt")
elif event.type == pygame.KEYDOWN:
print("Spieler hat Taste gedrückt")
if event.key == pygame.K_RIGHT:
print("Spieler hat Pfeiltaste rechts gedrückt")
elif event.key == pygame.K_LEFT:
print("Spieler hat Pfeiltaste links gedrückt")
elif event.key == pygame.K_UP:
print("Spieler hat Pfeiltaste hoch gedrückt")
elif event.key == pygame.K_DOWN:
print("Spieler hat Pfeiltaste runter gedrückt")
elif event.key == pygame.K_SPACE:
print("Spieler hat Leertaste gedrückt")
elif event.type == pygame.MOUSEBUTTONDOWN:
print("Spieler hast Maus angeklickt")
Und weil wir gerade bei den wichtigsten Tasten sind (falls wir 2 Spieler haben), sollten wir auch
die üblichen Tasten „w,a,s,d“ abfragen können. Diese Tastenkombination wurde mit dem Ego-
© https://www.python-lernen.de/pygame-tutorial.htm Seite 373
Shooter Quake 1996 bekannt. Die Abfrage läuft über das Kürzel pygame.K_a: - sprich
großes K (für Keyboard) und Unterstrich und dann die gewünschte Taste.
# Schleife Hauptprogramm
while spielaktiv:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
if event.type == pygame.QUIT:
spielaktiv = False
print("Spieler hat Quit-Button angeklickt")
elif event.type == pygame.KEYDOWN:
print("Spieler hat Taste gedrückt")
# genutzte Farbe
ORANGE = ( 255, 140, 0)
ROT = ( 255, 0, 0)
GRUEN = ( 0, 255, 0)
SCHWARZ = ( 0, 0, 0)
WEISS = ( 255, 255, 255)
# Fenster öffnen
screen = pygame.display.set_mode((640, 480))
# Schleife Hauptprogramm
while spielaktiv:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
if event.type == pygame.QUIT:
spielaktiv = False
print("Spieler hat Quit-Button angeklickt")
elif event.type == pygame.KEYDOWN:
print("Spieler hat Taste gedrückt")
# Spielfeld löschen
screen.fill(WEISS)
# Spielfeld/figuren zeichnen
# Fenster aktualisieren
pygame.display.flip()
# Refresh-Zeiten festlegen
clock.tick(60)
pygame.quit()
© https://www.python-lernen.de/pygame-tutorial.htm Seite 375
Uns somit haben wir unser Template für unsere Spiele. Auf diese Basis können wir aufbauen.
© https://www.python-lernen.de/pygame-installieren-mac-os-x.htm Seite 376
Hier in 5 Schritten
Terminal starten
Testen, ob Installation korrekt ausgeführt worden ist: Python Shell starten (über IDLE) >>>
import pygame
Rechtecke
Polygone
Kreise
Ellipsen
Linien
Wenn die Umrandung dicker sein soll, wird die letzte Zahl (hier die 1) einfach größer gewählt.
Wollen wir ein farbig ausgefülltes Rechteck, wird die letzte Zahl auf 0 gesetzt (weglassen hat
den gleichen Effekt). Das mag im ersten Augenblick irritieren, funktioniert aber. Einfach einmal
testen:
In unserem Beispiel startet die Linie an dem Punkt, der sich 10 Pixel von linken oberen Eck in X-
Richtung und 20 Pixel in Y-Richtung befindet und läuft zu dem X-Punkt 100 und Y-Punkt 120
© https://www.python-lernen.de/formen-zeichnen-pygame.htm Seite 379
Wir sehen eine Linie mit „Treppeneffekt“ – diesen Effekt können wir durch Antialiasing
beseitigen. Dafür gibt es in Pygame eine Anweisung (allerdings kann dann keine Strichstärke
mitgegeben werden):
Und in der Vergrößerung sieht man deutlich den Effekt der „gebügelten“ Linie.
Zeichnen wir zusätzlich ein Viereck mit denselben Angaben, dann ist deutlich, wie
Ellipsen/Kreise funktionieren.
Möchte man einen Kreis erhalten, dann muss die dritte und vierte Angabe, sprich die Breite und
die Höhe die gleiche Abmessung haben.
Kreisausschnitt zeichnen
Um einen Kreisausschnitt zu zeichnen, benötigen wir weitere Angaben als beim Kreis.
Allerdings sind die ersten Angaben identisch:
welche Farbe
wo startet der Kreisausschnitt? Bei der Uhr auf 3 Uhr (einfach einmal probieren)
Polygone zeichnen
Bei einem Polygon können beliebig viele Punkte angeben werden und somit ein beliebig
komplexes Gebilde erstellt werden.
Wenn wir uns den Aufbau der Koordinaten genau ansehen, sehen wir eine Liste in der weiteren
Liste geschachtelt sind.
Den Textinhalt
Dieser wird dann auf den Bildschirm an einer bestimmten Position gebracht
Schauen wir uns die 3 Schritte in Form von Python-Code an, dann wird die Vorgehensweise
schnell klar:
Wir erzeugen ein Schriftobjekt mit einer festgelegten Schriftart und Schriftgröße. Möchte man
einfach die Systemschrift nutzen, kann hier die Angabe „None“ erfolgen:
© https://www.python-lernen.de/formen-zeichnen-pygame.htm Seite 382
Schriftart
Schriftgröße
ob fett (bold)
ob kursiv (italics)
Textinhalt selber
Hier spielen 2 Spieler praktisch Tischtennis (Ping-Pong) und der Blick auf das
Spielfeld ist von oben auf die Platte, den Ball und die Schläger. Grafisch
extrem simpel – was bei der Erstveröffentlichung von Pong 1972 so möglich
war. Lustigerweise war der Begriff „Ping Pong“ geschützt und so wurde das Spiel Pong
genannt.
Wir wollen jetzt nur einen Ball animieren, der immer, wenn der den Fensterrand erreicht, wieder
im entsprechenden Winkel abprallt.
Dazu benötigen wir unser Grundgerüst aus dem Kapitel „Grundgerüst für Spiele mit Pygame“.
© https://www.python-lernen.de/pygame-animation.htm Seite 384
# genutzte Farbe
ORANGE = ( 255, 140, 0)
ROT = ( 255, 0, 0)
GRUEN = ( 0, 255, 0)
SCHWARZ = ( 0, 0, 0)
WEISS = ( 255, 255, 255)
# Fenster öffnen
screen = pygame.display.set_mode((640, 480))
# Schleife Hauptprogramm
while spielaktiv:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
if event.type == pygame.QUIT:
spielaktiv = False
print("Spieler hat Quit-Button angeklickt")
# Spielfeld löschen
screen.fill(SCHWARZ)
# Spielfeld/figuren zeichnen
# Fenster aktualisieren
pygame.display.flip()
# Refresh-Zeiten festlegen
clock.tick(60)
pygame.quit()
Bei unserem Klassiker ist der Hintergrund des Spielfelds schwarz. Daher können wir jedes Mal,
wenn wir unser Spielfeld neu aufbauen (sprich löschen) einfach unseren screen mit der
Farbe Schwarz füllen:
© https://www.python-lernen.de/pygame-animation.htm Seite 385
# Spielfeld löschen
screen.fill(SCHWARZ)
Zur Erinnerung. Die Konstanten für die Farben (wie z.B. SCHWARZ) haben wir am Anfang
unseres Pygame-Programmes definiert:
# genutzte Farbe
ORANGE = ( 255, 140, 0)
SCHWARZ = ( 0, 0, 0)
# Spielfeld/figuren zeichnen
pygame.draw.ellipse(screen, WEISS, [10,30,20,20])
Wir platzieren unseren Ball am Anfang mit dieser Anweisung an den Punkt X=10 und
Y=30
Allerdings wollen wir unseren Ball animieren. Also setzten wir diese Werte nicht fest
als Zahl, sondern nutzen Variablen. Nennen wir diese ballpos_x und
ballpos_y . Unsere Ballposition steckt also in diesen beiden Variablen, die wir vor
der Hauptroutine definieren müssen:
# Schleife Hauptprogramm
while spielaktiv:
Jetzt können wir diese Variablen beim Zeichnen unseres Kreises nutzen:
Unser Ball ruht nun in der Ecke und das Spiel wird extrem spannungslos ohne Bewegung (man
könnte auch langweilig dazu sagen).
# Schleife Hauptprogramm
while spielaktiv:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
if event.type == pygame.QUIT:
spielaktiv = False
# Spielfeld/figuren zeichnen
pygame.draw.ellipse(screen, WEISS, [ballpos_x, ballpos_y, 20, 20])
Hurra, unser Spielball bewegt sich nach unten rechts. Und hoppla – er verschwindet auf
Nimmerwiedersehen aus dem sichtbaren Bereich (und rollt unter irgendeinen Schrank
bestimmt).
Also müssen wir darauf reagieren, wenn der Ball den Spielrand erreicht. Über das Erstellen der
Fenstergröße wissen wir, ab wann der Ball aus dem sichtbaren Bereich verschwindet:
# Fenster öffnen
screen = pygame.display.set_mode((640, 480))
Und auch hier sollten wir nicht mit direkt eingetragenen Werten (im Beispiel 640 und 480)
arbeiten, sondern mit Variablen (oder in dem Fall Konstanten), da diese Größen sich ja während
dem gesamten Spielablauf nicht ändern.
FENSTERBREITE = 640
FENSTERHOEHE = 480
# Fenster öffnen
screen = pygame.display.set_mode((FENSTERBREITE, FENSTERHOEHE))
Die gewählten Begriffe im Deutschen sind zwar sehr lang, dafür sollte aber klar sein, welche
Werte sich dahinter verbergen. Und jetzt können wir kontrollieren, ob der Ball das sichtbare
Fenster verlassen möchte.
Überprüfen wir als Erstes, ob der Ball am unteren Rand ankommt. Hier wissen wir, wenn der
Wert der Variable ballpos_y größer ist als die Konstante FENSTERHOEHE , dann sollten wir
die Bewegungsrichtung ändern. Die Bewegungsrichtung ändern sich, indem wir die
ballpos_y wieder verkleinern. Anstelle von „plus 4“ werden wir dann „minus 4“ rechnen.
Also benötigen wir eine Abfrage, bevor wir unseren Kreis bewegen. Bisher haben wir für unsere
Bewegung:
© https://www.python-lernen.de/pygame-animation.htm Seite 387
Natürlich wollen wir auch hier nicht mit fest eingetragenen Werten wie im Beispiel „4“ arbeiten,
sondern auch hier eine Variable nutzen. Eigentlich sollten wir die Variablen nennen wie z.B.
„bewegungsaenderung_x“ – aber das ist deutlich zu lang. Wir nutzen dafür die Variablen mit
der Bezeichnung bewegung_x und bewegung_y . Auch diese müssen außerhalb unserer
Hauptschleife das erste Mal festgelegt werden, um dann in der Hauptschleife genutzt zu
werden.
bewegung_x = 4
bewegung_y = 4
Jetzt wollen wir über eine if -Abfrage die Berührung des Fensterrands kontrollieren:
Das wäre im ersten Augenblick eine Variante, die aber leider dazu führt, dass der Ball bei
Verlassen des unteren Fensterbereichs nicht nach oben fliegt, sondern dann nach rechts
wegrutscht.
Wir müssen also EINMAL die Bewegungsrichtung ändern. Dazu nutzen wir den
mathematischen Trick von * -1 . So können wir die Bewegungsrichtung „umschalten“. Zur
Erinnerung an die alten Schulzeiten die 2 wichtigen Fälle von „mal minus 1“:
Haben wir ein + wird durch * -1 aus dem Plus ein Minus.
Haben wir ein – wird durch * -1 aus dem Minus ein Plus.
Die benötigten Variablen für die beiden Bewegungsrichtungen haben wir bereits und können
dann darauf unsere Mathematik anwenden.
Wenn man es testet, dann verschwindet der Ball fast unten (darum kümmern wir uns später)
und springt dann nach oben, um rechts zu verschwinden. Also kümmern wir uns um den
rechten Rand. Hier dieselbe Vorgehensweise, nur für unsere x-Bewegung:
Jetzt überlebt unser Ball unten und rechts, aber verschwindet oben aus dem Fensterrahmen
© https://www.python-lernen.de/pygame-animation.htm Seite 388
bzw. links. Also auch hierfür die entsprechende Abfrage wobei wir einfach mit 0 vergleichen
(was den oberen und den linken Fensterrand darstellt):
if ballpos_y < 0:
bewegung_y = bewegung_y * -1
if ballpos_x < 0:
bewegung_x = bewegung_x * -1
Das funktioniert zwar, aber kürzer ist schöner – also machen wir aus den 8 Zeilen nur noch 4
und fassen die if -Abfragen zusammen:
Jetzt haben wir noch den Schönheitsfehler, dass der Ball unten und rechts aus dem sichtbaren
Bereich fast verschwindet. Unsere Rechnung ist bisher nicht exakt richtig: wir vergleichen die
Ballposition mit der Fensterbreite (bzw. Höhe). Aber eigentlich ist die Breite (bzw. Höhe des
Balls) auch noch ausschlaggebend. Daher sollten wir berechnen:
(FENSTERHOEHE – Balldurchmesser)
Und auch hier gehört eine Variable (bzw. Konstante her). Wir müssen diese Konstante bereits
(wie die anderen auch) im Vorfeld definieren, können diese beim Zeichnen unseres Balls
verwenden und dann bei der if -Abfrage einsetzen:
Wieder wollen wir einen sprechenden Namen haben – wer die mathematischen Bezeichnungen
gewohnt ist, wird „d“ für Durchmesser nehmen, sprich die Konstantenbezeichnung wäre dann
„BALL_D“ – wir nutzen lieber für 100 % Transparenz den wuchtigen Namen:
BALL_DURCHMESSER“
BALL_DURCHMESSER = 20
Und somit haben wir einen wunderbar herum springenden Ball. Wir können die Spielfeldgröße,
Ballgröße und Geschwindigkeit durch Ändern der Werte bei der entsprechenden Variablen
(bzw. Konstanten) schnell anpassen und alle Programmteile reagieren darauf.
# genutzte Farbe
ORANGE = ( 255, 140, 0)
ROT = ( 255, 0, 0)
GRUEN = ( 0, 255, 0)
SCHWARZ = ( 0, 0, 0)
WEISS = ( 255, 255, 255)
FENSTERBREITE = 640
FENSTERHOEHE = 480
# Fenster öffnen
screen = pygame.display.set_mode((FENSTERBREITE, FENSTERHOEHE))
BALL_DURCHMESSER = 20
bewegung_x = 4
bewegung_y = 4
# Schleife Hauptprogramm
while spielaktiv:
© https://www.python-lernen.de/pygame-animation.htm Seite 390
while spielaktiv:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
if event.type == pygame.QUIT:
spielaktiv = False
# Spielfeld löschen
screen.fill(SCHWARZ)
# Spielfeld/figuren zeichnen
pygame.draw.ellipse(screen, WEISS, [ballpos_x, ballpos_y, BALL_DURCHMESSER
# Fenster aktualisieren
pygame.display.flip()
# Refresh-Zeiten festlegen
clock.tick(60)
pygame.quit()
quit()
© https://www.python-lernen.de/pygame-tastatur-abfragen.htm Seite 391
Im ersten Schritt werden wir die Spielerfigur mit der Tastatur steuern – in einem folgenden
Kapitel wird die Abfrage der Maus und Game-Controller über Pygame gezeigt.
Wir benötigen unser Grundgerüst aus dem Kapitel „Grundgerüst für Spiele mit Pygame“.
Als Erstes benötigen wir eine Spielerfigur – aus dem letzten Kapitel mit Pong benötigen wir
einen Tischtennisschläger. Dieser wird Grafisch ganz simpel über ein Rechteck dargestellt.
Auch hier benötigen wir wieder die Definition der Variablen außerhalb unsere Hauptroutine.
spielfigur_1_x
spielfigur_1_y
Diese setzen wir auf die linke Spielbrettseite an die Position X = 20 und Y = 20:
spielfigur_1_x = 20
spielfigur_1_y = 20
# Schleife Hauptprogramm
while spielaktiv:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
Nun zeichnen wir innerhalb der Hauptroutine den Tischtennisschläger des ersten Spielers:
# Spielfeld/figuren zeichnen
# -- Ball
pygame.draw.ellipse(screen, WEISS, [ballpos_x, ballpos_y, BALL_DURCHMESSER, BALL_DURCH
# -- Spielerfigur 1
pygame.draw.rect(screen, WEISS, [spielfigur_1_x, spielfigur_1_y, 20, 100])
spielfigur_1_x = 20
spielfigur_1_y = 20
spielfigur_1_bewegung = 0
# Schleife Hauptprogramm
while spielaktiv:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
if event.type == pygame.QUIT:
spielaktiv = False
print("Spieler hat Quit-Button angeklickt")
elif event.type == pygame.KEYDOWN:
print("Spieler hat Taste gedrückt")
Zusätzlich erweitern wir unsere Programmcodevorlage um die Möglichkeit, das Spiel auch mit
der Escape-Taste beenden zu können. Somit kann das Spiel entweder über das Schließen des
Fensters oder über die Escape-Taste beendet werden:
Aber der Reihe nach – vor dem Zeichnen kommt die Berechnung. Dazu haben wir im Ablauf
unseres Programms den Punkt „# Spiellogik“ vorgesehen. Danach zeichnen wir frisch den
Schläger. Dazu müssen wir einfach die bisher fixen Werte durch das Ergebnis der neuen
Variablen spielfigur_1_bewegung ersetzen.
© https://www.python-lernen.de/pygame-tastatur-abfragen.htm Seite 393
spielfigur_1_bewegung = 0
# Schleife Hauptprogramm
while spielaktiv:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
if event.type == pygame.QUIT:
spielaktiv = False
print("Spieler hat Quit-Button angeklickt")
if event.type == pygame.KEYDOWN:
print("Spieler hat Taste gedrückt")
# Spiellogik
if spielfigur_1_bewegung != 0:
spielfigur_1_y += spielfigur_1_bewegung
Die Position des Schlägers darf nicht kleiner als 0 werden. Dazu Überprüfen wir die y-Position
und wird diese kleiner als 0, setzten wird diese einfach wieder auf 0 zurück. Dies ist die
einfachere Möglichkeit als viel Aufwand zu treiben und im Vorfeld darauf zu überprüfen.
# Spiellogik
if spielfigur_1_bewegung != 0:
spielfigur_1_y += spielfigur_1_bewegung
if spielfigur_1_y < 0:
spielfigur_1_y = 0
Wenn wir das Gleich für den unteren Fensterbereich machen wollen, dann sollten wir unbedingt
die Höhe des Schlägers berücksichtigen. Die erste gezeigte Variante ist suboptimal:
Und noch besser ist, wenn wir wieder mit Variablen arbeiten (hier kann man sich streiten, ob
das auch eine Konstante sein sollte). Aber einfach einmal als Gedanken für mehr Spielspaß,
© https://www.python-lernen.de/pygame-tastatur-abfragen.htm Seite 394
dass der Schläger umso kleiner wird, je länger das Spiel läuft als Spielerschwernis. Daher
machen wir eine Variable.
spielfigur_1_bewegung = 0
schlaegerhoehe = 100
# Schleife Hauptprogramm
# Spiellogik
if spielfigur_1_bewegung != 0:
spielfigur_1_y += spielfigur_1_bewegung
if spielfigur_1_y < 0:
spielfigur_1_y = 0
# Spielfeld löschen
screen.fill(SCHWARZ)
# Spielfeld/figuren zeichnen
# -- Ball
pygame.draw.ellipse(screen, WEISS, [ballpos_x, ballpos_y, BALL_DURCHMESSER, BALL_DURCH
# -- Spielerfigur 1
pygame.draw.rect(screen, WEISS, [spielfigur_1_x, spielfigur_1_y, 20, schlaegerhoehe
Zweiter Spieler
Das war die Steuerung für die erste Spielfigur. Jetzt benötigen wir es für die Zweite. Hier gibt
es die Variante, einfach wieder so vorzugehen wie wir es bei der ersten Spielfigur gemacht
haben oder eine schönere Lösung über Funktionen (was wir später machen). Bei 2 Spielern
wählen wir den erst einmal den simplen Weg, was wir später durch Funktionen dann ändern.
Didaktisch wichtig ist, langsam das Verständnis aufzubauen.
spielfigur_1_x = 20
spielfigur_1_y = 20
spielfigur_1_bewegung = 0
schlaegerhoehe = 60
# Schleife Hauptprogramm
Bei den Tasten, die wir für die Steuerung auswählen, nutzen wir nun aus Tradition die Tasten
w und s .
# Schleife Hauptprogramm
while spielaktiv:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
if event.type == pygame.QUIT:
spielaktiv = False
print("Spieler hat Quit-Button angeklickt")
if event.type == pygame.KEYDOWN:
print("Spieler hat Taste gedrückt")
# Spiellogik
if spielfigur_1_bewegung != 0:
spielfigur_1_y += spielfigur_1_bewegung
if spielfigur_1_y < 0:
spielfigur_1_y = 0
if spielfigur_2_bewegung != 0:
spielfigur_2_y += spielfigur_2_bewegung
if spielfigur_2_y < 0:
spielfigur_2_y = 0
# Spielfeld/figuren zeichnen
# -- Ball
pygame.draw.ellipse(screen, WEISS, [ballpos_x, ballpos_y, BALL_DURCHMESSER, BALL_DURCH
# -- Spielerfigur 1
pygame.draw.rect(screen, WEISS, [spielfigur_1_x, spielfigur_1_y, 20, schlaegerhoehe
# -- Spielerfigur 2
pygame.draw.rect(screen, WEISS, [spielfigur_2_x, spielfigur_2_y, 20, schlaegerhoehe
Somit haben wir die Interaktion vom den 2 Spieler eingebaut, die nun Ihre Schläger bewegen
können. Nun sollte der Ball noch entsprechend reagieren, wenn dieser auf die Schläger auftrifft:
Wir benötigen eine Kollisionskontrolle. Diese schauen wir uns im folgenden Kapitel an.
K_RETURN Return
K_TAB Tab-Taste
K_ESCAPE Escape
K_SPACE Leertaste
K_COMMA , Komma
K_MINUS - Minus
K_SLASH / Schrägstrich
K_0 0
K_1 1
K_2 2
K_3 3
K_4 4
K_5 5
K_6 6
K_7 7
K_8 8
K_9 9
K_SEMICOLON ; Semikolon
K_EQUALS = Gleichheitszeichen
K_BACKSLASH Rückwärtsschrägstrich
K_a a
K_b b
K_c c
K_d d
K_e e
K_f f
K_g g
K_h h
K_i i
K_j j
K_k k
K_l l
K_m m
K_n n
K_o o
K_p p
K_q q
© https://www.python-lernen.de/pygame-tastatur-abfragen.htm Seite 399
K_r r
K_s s
K_t t
K_u u
K_v v
K_w w
K_x x
K_y y
K_z z
K_KP0 Zehnerblock 0
K_KP1 Zehnerblock 1
K_KP2 Zehnerblock 2
K_KP3 Zehnerblock 3
K_KP4 Zehnerblock 4
K_KP5 Zehnerblock 5
K_KP6 Zehnerblock 6
K_KP7 Zehnerblock 7
K_KP8 Zehnerblock 8
K_KP9 Zehnerblock 9
K_F1 F1
K_F2 F2
K_F3 F3
K_F4 F4
K_F5 F5
K_F6 F6
K_F7 F7
K_F8 F8
K_F9 F9
K_F10 F10
K_F11 F11
K_F12 F12
K_CAPSLOCK Feststelltaste
Dazu müssen wir im Programm auch mitbekommen, ob der Ball den Schläger berührt oder
verfehlt. Dazu ist eine Kollisionskontrolle im Pygame integriert, die das für uns als
Programmierer sehr einfach macht. Diese Anweisung ist colliderect . Wenn wir die
Anweisung ansehen, steckt dort 2 Wörter darin: collide (engl. für „kollidieren“) und die
Abkürzung rect (rectangle) steht für ein Rechteck.
Wir können also mit einem Befehl überprüfen, ob eine Kollision zwischen 2 Rechtecken
vorliegt. Auch wenn unser Ball als Kreis gezeichnet ist, funktioniert die Kollisionskontrolle
trotzdem hervorragend. Wir wollen unsere Spielerfigur player1 und unseren Spielball
ball auf eine Kollision überprüfen:
player1.colliderect(ball)
Wir erhalten bei der Kontrolle auf eine Kollision zwischen der Spielerfigur und dem Ball ein
True als Rückgabewert, wenn eine Kollision vorliegt. Also können wir hier eine if -Abfrage
durchführen:
if player1.colliderect(ball):
print("Zusammenstoß Spieler 1 und Ball")
Jetzt müssen wir darauf reagieren und die X-Bewegung umdrehen. Mathematisch
funktioniert das über das Multiplizieren mit -1:
if player1.colliderect(ball):
print("Zusammenstoß Spieler 1 und Ball")
bewegung_x = bewegung_x * -1
Wenn wir den Code probieren, dann sieht die Bewegung sehr merkwürdig aus und wir
bekommen als Rückmeldung in der Konsole, dass es mehrere Kollisionen gab. Was ist
passiert. Da unser Ball sich mit einer Geschwindigkeit von 6 Pixeln bewegen kann, wird die
Kollision irgendwo zwischen Pixel 1 und 6 vom Programm erst wahrgenommen. Pro
Durchgang in der Hauptroutine liegt immer 6 Pixel Unterschied zur letzten Ballposition.
Würde die gleich am Anfang liegen (Pixel 1) würde er wie gewünscht abprallen. Liegt die
Kollision allerdings bei Pixel 2, ändert er die Richtung, aber es liegt sofort wieder eine
Kollision vor und er ändert wieder die Richtung. Das kann einige Male passieren. So eine
Reaktion wollen wir nicht wirklich.
Um uns nicht in ewigen Berechnungen zu verlieren, setzen wir die Ballposition ballpos_x
einfach vor dem Schläger und fertig.
if player1.colliderect(ball):
print("Zusammenstoß P1")
bewegung_x = bewegung_x * -1
ballpos_x = 40
wir können bei jedem Ballwechsel die Größe des Schlägers verkleinern und somit das Spiel
schwieriger machen
© https://www.python-lernen.de/pygame-kollisions-kontrolle.htm Seite 402
Um die Ballwechsel zu zählen, benötigen wir noch eine Variable ballwechsel , die wir vor
der Schleife erstellen müssen, damit wir diese bei Kollision erhöhen können.
ballwechsel = 0
# Schleife Hauptprogramm
while spielaktiv:
if player1.colliderect(ball):
print("Zusammenstoß P1")
bewegung_x = bewegung_x * -1
ballpos_x = 40
ballwechsel += 1
Wollen wir noch die Größe des Schlägers beeinflussen, dann verkleinern wir die Variable für
die Schlägerhöhe:
if player1.colliderect(ball):
print("Zusammenstoß P1")
bewegung_x = bewegung_x * -1
ballpos_x = 40
ballwechsel += 1
schlaegerhoehe -= 5
Das Ganze müssen wir noch für den zweiten Spieler genauso machen, allerdings wird dort die
Ballposition links vor dem Schläger gesetzt. Die brachiale Variante ist ballpos_x = 570 -
besser wäre die Berechnung über unsere Konstante für Spielfeldbreite und Schlägerbreite
(darf man machen, wenn alles so weit funktioniert – daher hier die brachiale Variante:
if player2.colliderect(ball):
print("Zusammenstoß P2")
bewegung_x = bewegung_x * -1
ballpos_x = 570
ballwechsel += 1
schlaegerhoehe -= 5
Und nun können wir endlich das Spiel richtig testen. Viel Spaß beim ersten Match:
# Fenster aktualisieren
pygame.display.flip()
# genutzte Farbe
ORANGE = ( 255, 140, 0)
ROT = ( 255, 0, 0)
GRUEN = ( 0, 255, 0)
SCHWARZ = ( 0, 0, 0)
WEISS = ( 255, 255, 255)
FENSTERBREITE = 640
FENSTERHOEHE = 480
# Fenster öffnen
screen = pygame.display.set_mode((FENSTERBREITE, FENSTERHOEHE))
BALL_DURCHMESSER = 20
bewegung_x = 4
bewegung_y = 4
spielfigur_1_x = 20
spielfigur_1_y = 20
spielfigur_1_bewegung = 0
schlaegerhoehe = 220
ballwechsel = 0
# Schleife Hauptprogramm
while spielaktiv:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
if event.type == pygame.QUIT or event.type == pygame.KEYDOWN and event.key ==
© https://www.python-lernen.de/pygame-kollisions-kontrolle.htm Seite 404
spielaktiv = False
print("Spieler hat Quit-Button angeklickt")
if event.type == pygame.KEYDOWN:
print("Spieler hat Taste gedrückt")
# Spiellogik
if spielfigur_1_bewegung != 0:
spielfigur_1_y += spielfigur_1_bewegung
if spielfigur_1_y < 0:
spielfigur_1_y = 0
if spielfigur_2_bewegung != 0:
spielfigur_2_y += spielfigur_2_bewegung
if spielfigur_2_y < 0:
spielfigur_2_y = 0
# Spielfeld löschen
screen.fill(SCHWARZ)
# Spielfeld/figuren zeichnen
# -- Ball
ball = pygame.draw.ellipse(screen, WEISS, [ballpos_x, ballpos_y, BALL_DURCHMESSER
# -- Spielerfigur 1
player1 = pygame.draw.rect(screen, WEISS, [spielfigur_1_x, spielfigur_1_y, 20, schlaeg
# -- Spielerfigur 2
player2 = pygame.draw.rect(screen, WEISS, [spielfigur_2_x, spielfigur_2_y, 20, schlaeg
# if ball.colliderect(player1):
if player1.colliderect(ball):
print("Zusammenstoß P1")
bewegung_x = bewegung_x * -1
ballpos_x = 40
ballwechsel += 1
schlaegerhoehe -= 5
if player2.colliderect(ball):
print("Zusammenstoß P2")
bewegung_x = bewegung_x * -1
ballpos_x = 570
ballwechsel += 1
schlaegerhoehe -= 5
# Fenster aktualisieren
pygame.display.flip()
# Refresh-Zeiten festlegen
clock.tick(60)
pygame.quit()
© https://www.python-lernen.de/pygame-kollisions-kontrolle.htm Seite 406
© https://www.python-lernen.de/pygame-spiele-sound-hintergrundmusik.htm Seite 407
In Pygame sind sowohl Soundeffekte wie auch Hintergrundmusik kein großer Aufwand.
Wichtig ist, dass einem entsprechende Musik- und Sounddateien vorliegen. Wichtig dabei ist,
dass wir für die Soundeffekte das Format .WAV benötigen. Die Hintergrundmusik kann auch
eine MP3-Datei sein bzw. MIDI-File.
Woher nehmen, wenn nicht stehlen? Hier kann Google bemühen. Einfach nach „midi download
kostenlos“ suchen. Für WAV- und MP3-Dateien kann man sich z.B. bei
„https://soundbible.com/“ umschauen.
# Musik/Soundeffekte einrichten
pygame.mixer.music.load('sound/eine-MP3-Datei.mp3')
Wollen wir eine MIDI-Datei nutzen, sieht der Aufruf wie folgt aus:
pygame.mixer.music.load('sound/eine-midi-datei.mid')
Somit haben wir die Musikdatei geladen. Das bedeutet aber noch nicht, dass diese
automatisch abgespielt wird. Dazu müssen wir noch den „Play“-Button in Pygame drücken.
# Musik/Soundeffekte einrichten
pygame.mixer.music.load('sound/eine-MP3-Datei.mp3')
pygame.mixer.music.play(-1,0.0)
Über Play-wird das abspiele der Musik gestartet. Die Werte in der Klammer haben natürlich
auch eine Bedeutung:
Erster Wert bestimmt die Anzahl. Wobei die Zahl 0 bedeutet, dass das Musikstück einmal
abgespielt wird. Tragen wir 5 ein, erhalten wir 6-mal das abspielen. Tragen wir hier -1 ein, dann
wird das Musikstück immer wieder wiederholt (sprich unendlich abgespielt).
Der zweite Wert sagt, ab welchem Zeitpunkt das Musikstück abgespielt werden soll. Wir wollen
es von Anfang an, daher geben wir 0.0 an. Dabei ist auch noch das Musikformat für die Art der
Angabe unterschiedlich. Bei MP3 und OGG sind es Sekundenangaben. Bei MOD ist es die
„Pattern order number“. Und bei MIDI funktioniert keine Zeitangabe.
© https://www.python-lernen.de/pygame-spiele-sound-hintergrundmusik.htm Seite 408
Musiklautstärke einstellen
Jetzt sollten wir Hintergrundmusik spielen haben. Zusätzlich können wir noch die Lautstärke
über die Anweisung pygame.mixer.music.set_volume() angeben. Die möglichen Werte
liegen zwischen 0 und 1 – 0 für unhörbar und 1 für maximale Lautstärke.
pygame.mixer.music.load('sound/eine-MP3-Datei.mp3')
pygame.mixer.music.play(-1,0.0)
pygame.mixer.music.set_volume(.6)
Das Einstellen der Lautstärke für die Hintergrundmusik ist wichtig. Die Hintergrundmusik soll ja
nicht die Soundeffekte vom Spiel überdecken.
In unserem Spiel soll beispielsweise durch Drücken der Taste p die Pause aktiviert werden,
pausieren wir auch die Musik. In folgendem Beispiel wird die Taste p doppelt belegt. Ist keine
Pause, wird pausiert. Ist bereits die Pause aktiviert, dann wird diese aufgehoben und die Musik
spielt weiter. Zusätzlich wird der Ball noch eingefroren bzw. beim Beenden der Pause seine
ursprünglichen Werte wieder genutzt:
# Spiel pausieren
elif event.key == pygame.K_p:
print("Spiel pausieren")
if spielpause == True:
spielpause = False
pygame.mixer.music.unpause()
bewegung_x = spielpause_x
bewegung_y = spielpause_y
else:
spielpause = True
pygame.mixer.music.pause()
spielpause_x = bewegung_x
spielpause_y = bewegung_y
bewegung_x = 0
bewegung_y = 0
Hier kommt ein anderer Befehl wie bei der Hintergrundmusik zum Einsatz.
getroffen = pygame.mixer.Sound('sound/treffer.wav')
Über diese Pygame-Anweisung erstellen wir ein neues Sound-Objekt. Auf dieses können wir im
folgenden Zugreifen.
© https://www.python-lernen.de/pygame-spiele-sound-hintergrundmusik.htm Seite 409
Irritierend ist hier die Schreibweise. Hier wird auf einmal das „S“ bei der Anweisung
großgeschrieben. Bei der Hintergrundmusik pygame.mixer.music.load war alles noch
Kleinschreibung. Merkwürdig aber so ist es eben. Hält man sich nicht daran, erhält man einen
Traceback-Fehler „AttributeError: module 'pygame.mixer' has no attribute 'sound'“
Nachdem wir nun unser Objekt erzeugt haben, können wir auf dieses Zugreifen. Wir wollen den
Sound abspielen – dazu benötigen wir die Anweisung.
Jetzt wird dies noch an der entsprechenden Stelle in unserem Spiel integriert und wir haben
deutlich mehr Spielspaß:
# if ball.colliderect(player1):
if player1.colliderect(ball):
print("Zusammenstoß P1")
pygame.mixer.Sound.play(getroffen)
# … restlicher Aktionscode
if player2.colliderect(ball):
print("Zusammenstoß P2")
pygame.mixer.Sound.play(getroffen)
# … restlicher Aktionscode
Das war es auch schon – und nun viel Spaß beim Heraussuchen der passenden Musik und
Soundeffekte für das Spiel. Dadurch kann man einem Spiel einen ganz eigenen Charakter
verpassen (oder es extrem nervig machen).
© https://www.python-lernen.de/koordinatensystem-computerspiel.htm Seite 410
Als Erstes schauen wir uns einfach das aus Schulzeiten vielleicht noch bekannte kartesische
Koordinatensystem an. Wer sich nicht mehr an die Schulzeiten erinnert (oder es bisher nicht
kennengelernt hat) – jetzt bekommt Mathe endlich eine praktische Anwendung. Aber keine
Panik: es ist keine wilde Rechnerei, sondern es geht um das Verständnis zwischen
Koordinatensystem und die Anwendung beim Programmieren!
Das kartesische Koordinatensystem wurde von dem Franzosen René Descartes entwickelt.
Dabei war es damals hip, Latein zu verwenden und so wurde das Koordinatensystem nach
dem latinisierten Nachnamen von Descartes, also „Cartesius“ benannt (wir müssen jetzt nicht
Latein lernen, aber manchmal kann man im Klugscheißermodus beeindrucken).
In dieses Koordinatensystem können wir nun über Pygame einfach etwas einzeichnen:
Rechteck im Koordinatensystem
Unsere erste Angabe mit 20 bezieht sich auf die x-Achse und die zweite Angabe mit 50 bezieht
sich auf die y-Achse. Das Viereck wird als an der Position 20 (rechts vom Nullpunkt) und an der
Position 50 (nach unten vom Nullpunkt aus gesehen) gezeichnet. Es ist jeweils 30 Pixel breit
wie hoch.
Wir geben auf dem Bildschirm (in einem Fenster) unsere Spielgrafik aus, aber im Hintergrund
haben wir eine ineinander verschachtelte Liste, durch die wir bequem unsere 2-dimensionale
Spielekarte (map) darstellen können und Ereignisse berechnen. Schauen wir uns diese Listen
an:
Unsere Liste – man könnte auch Karte dazu sagen (oder map hört sich auch gut an):
Wir haben also an der dritten Position Essen, dass wir einsammeln wollen und dann kommen 2
Bergelemente, die wir so nicht überwinden können um das darauffolgende Essen einsammeln
zu können.
In Python kann man den Inhalt eines bestimmten Listenfeldes über den Index abfragen. Wollen
wir nun die dritte Position abfragen und wir denken, da müsste doch ein „E“ für Essen
herauskommen, wird sich wundern. Es kommt ein B!
Kleine Gemeinheit am Rande. Wir können den Inhalt von Listen sehr einfach abfragen. Aber der
Index fängt bei 0 an – sprich unser erstes Element ist also karte[0] . Unser drittes Element
aus unserem obigen Beispiel sprechen wir an über:
Für die Vorstellungskraft: immer Minus 1 und dann passt das mit Index ab 0 :)
karte = [0, 0, 1, 7, 7, 1, 0, 1]
Also wollen auch eine weitere Zeile – unsere Karte wird somit 2-Dimensional. In Python werden
verschachtelte Listen einfach über ein Komma getrennt und das komplette Element wird durch
eine weitere eckige Klammer umschlossen. Die unübersichtliche Schreibweise wäre, alles in
eine Zeile zu schreiben (hier einmal, dass man es sich nicht angewöhnt):
In der zweiten Zeile kommt eine 5 als erste Angabe (das könnte eine Höhle darstellen). Diese
Angabe ist wichtig für das Verständnis im Folgenden:
© https://www.python-lernen.de/koordinatensystem-computerspiel.htm Seite 415
Und die schönere Darstellung ist (weil man sich dann fast schon die Landschaft vorstellen
kann) einfach untereinander:
karte = [
[0, 0, 1, 7, 7, 1, 0, 1],
[5, 0, 0, 1, 0, 0, 0, 7]
]
Für die Abfrage einer Position müssen wir nun sowohl die x-Achse wie die y-Achse angeben:
karte = [
[0, 0, 1, 7, 7, 1, 0, 1],
[5, 0, 0, 1, 0, 0, 0, 7]
]
print(karte[1][0])
Aber hoppla – was kommt da nun raus? Als Rückgabewert erhalten wir „5“ und nicht „0“.
Warum? Bei verschachtelten Listen haben wir den Unterschied zum kartesischen
Koordinatensystem, dass die erste Angabe die Zeile ausmacht, sprich Y und die zweite Angabe
dann X!
Das folgende Bild soll es klarer machen, wenn wir die Position karte[1][3] auslesen
wollen:
Wir werden von unserer Spielfigur den „Aufenthaltsort“ in 2 weiteren Variablen speichern.
Vorteil: wir können auf unserer Karte nachschauen, was je nach Zugrichtung passieren würde
(und den Zug dann unter Umständen nicht zulassen).
spielfigur_x = 0
spielfigur_y = 0
Jetzt können wir die Anweisung geben, dass die Figur sich nach rechts bewegt. Bevor wir die
Figur bewegen, überprüfen wir, ob in unserer Karte rechts neben unsere Spielfigur ein Berg
befindet, wo die Figur sich nicht hinbewegen kann. Also ein kleiner Check über unsere Karte:
Hier sieht man auch den Vorteil von Zahl. Wir könnten in unserem Spiel zusätzliche
unüberwindbare Bereiche einbauen. Neben Berge (7) gibt es noch Flüsse (8) und Schluchten
(9). Und somit wäre unsere Abfrage einfach anstelle von „==“ einfach „>=“
© https://www.python-lernen.de/koordinatensystem-computerspiel.htm Seite 416
Unsere Mauersteine werden für eine Vereinfachung als Quadrate (alle Seiten sind gleich lang)
umgesetzt. Es geht hier um die Vorgehensweise und nicht um eine unnötige Komplizierung.
Wer Spaß hat, kann am Ende sich eine Breakout-Variante mit länglichen Ziegelsteinen basteln.
Unser Ball ist gleich Breit (und somit auch gleich hoch) wie die Ziegelsteine. Somit können wir
sehr einfach überprüfen, ob er im nächsten Bewegungsschritt einen Stein trifft.
Wir können also unser Spielfeld einfach über das Koordinatensystem aufbauen. Allerdings
haben die Mauersteine eine vorgegebene Größe. Wir geben unseren Spielsteinen eine
Feldbreite von 20 Pixel und eine Feldhöhe von 20 Pixeln. Die Zahl 20 ist schön einfach auch im
Kopf zu rechnen.
Unser Spielfeld selber soll bis zu 20 Ziegelsteine nebeneinander darstellen können – somit ist
es 20 x 20 = 400 Pixel breit (unsere Gesamtbreite). Die Spielfeldhöhe soll 30 Positionen haben
– sprich wir haben die Feldhöhe 20 mal 30 mögliche Positionen – sprich 30 x 20 = 600 Pixel
Gesamthöhe. Wir haben also einen Multiplikator (Faktor), den wir immer wieder im ganzen
Spiel nutzen – sprich diesen setzen wir als Konstante im Spiel ein.
Hier nun unbedingt von Anfang an mit diesem Multiplikator rechnen. Somit ist eine Änderung
der Spielfeldgröße extrem einfach umsetzbar. Hier unsere ersten Programmzeilen:
© https://www.python-lernen.de/breakout-spiel-programmieren.htm Seite 418
# unser Multiplikator
MULTIPLIKATOR = 20
Jetzt kommt unsere typische Schleife für unser Hauptprogramm. Diese wie bereits aus dem
bisherigen Kapitel einsetzt mit der Möglichkeit, dass der Spieler das Spiel über die Escape-
Taste beenden kann. Da wir diese Vorgehensweise schon öfters im Kurs gemacht haben, keine
große Erklärung dazu (wenn gewünscht, einfach in den entsprechenden Kapiteln
nachschlagen).
# unser Multiplikator
MULTIPLIKATOR = 20
# Schleife Hauptprogramm
while spielaktiv:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
if event.type == pygame.QUIT or event.type == pygame.KEYDOWN and event.key ==
spielaktiv = False
print("Spieler hat beendet")
# Fenster aktualisieren
pygame.display.flip()
# Refresh-Zeiten festlegen
clock.tick(10)
pygame.quit()
Wir bekommen nun unser Spielfenster mit der Größe 400 auf 600 Pixel erstellt. Ändern wir die
Konstante „MULTIPLIKATOR“, ändert sich automatisch die Größe des Fensters – später auch
automatisch die Größe der Spielelemente.
© https://www.python-lernen.de/breakout-spiel-programmieren.htm Seite 419
© https://www.python-lernen.de/breakout-spielgegner-mauersteine-zeichnen.htm Seite 420
Mauersteine zeichnen
Wir setzen zum Zeichnen der Mauersteine als Grundlage eine ineinander verschachtelte Liste
ein (siehe Kapitel Listen). Diese verschachtelte Liste dient einerseits zum ersten Zeichnen
unsere Spielelemente „Mauersteine“ und während dem Spiel zur Kollisionskontrolle. Hier haben
wir einen großen Unterschied zum Kapitel mit Pong. Wir selber überprüfen, ob eine Kollision
vorliegt und können dann darauf reagieren. Somit wären auch unterschiedliche Reaktionen
möglich (zum Beispiel trifft man einen grünen Ziegelstein, wird der Ball schneller – trifft man
einen braunen Ziegelstein könnte der Ball langsamer werden – das nur zum gedanklich
durchspielen, warum gerne eine Kollisionskontrolle nicht aus der Hand gibt).
Aber zeichnen wir erst einmal unsere Ziegelsteine. Zum Zeichnen erstellen wir uns eine
Funktion, der wir nur das gewünschte Feld mitgeben. Die Berechnung, auf welcher x- und y-
Position das Feld sich befindet, wird in der Funktion über die Konstante „MULTIPLIKATOR“
erledigt.
Die Funktion nennen wir element_zeichnen() und übergeben von unserem Feld dann die
Reihen- und die Spaltennummer. Bauen wir Schritt für Schritt die Funktion auf. Wir benötigen
auch noch Farben, die wir wie gewohnt definieren:
# genutzte Farben
ORANGE = ( 255, 140, 0)
# Spielelement zeichnen
def element_zeichnen(spalte,reihe):
pygame.draw.rect(fenster, ORANGE,(spalte*MULTIPLIKATOR, reihe*MULTIPLIKATOR,MULTIPLIKA
Wenn wir nun ein Spielelement zeichnen wollen, dann können wir einfach die Funktion
aufrufen:
# genutzte Farben
ORANGE = ( 255, 140, 0)
# Spielelement zeichnen
def element_zeichnen(spalte,reihe):
pygame.draw.rect(fenster, ORANGE,(spalte*MULTIPLIKATOR, reihe*MULTIPLIKATOR,MULTIPLIKA
Wir erhalten als Ergebnis des Zeichnens der 4 Spielelemente dann folgendes Aussehen:
© https://www.python-lernen.de/breakout-spielgegner-mauersteine-zeichnen.htm Seite 421
Unsere letzte Position ist daher nicht Spalte 20, sondern Spalte 19
Start bei 0 ist Ok. Das ist das übliche Verhalten von den allermeisten Programmiersprachen.
Wichtig ist einfach, dass man bei der Entwicklung daran denkt.
Damit wir einen guten Eindruck vom Aussehen bekommen, wird der Hintergrund in der
endgültigen Farbe Weiß gezeichnet:
# genutzte Farben
ORANGE = ( 255, 140, 0)
SCHWARZ = ( 0, 0, 0)
WEISS = ( 255, 255, 255)
# Hintergrundfarbe Fenster
fenster.fill(WEISS)
Als Erstes erstellen wir eine neue Funktion mit dem Namen kor() . Diese berechnet den
Korrekturfaktor und gibt den korrigierten Wert zurück. Dadurch wird unsere Funktion
element_zeichnen() deutlich übersichtlicher:
def kor(zahl):
zahl = zahl * MULTIPLIKATOR
return zahl
# Spielelement zeichnen
def element_zeichnen(spalte,reihe):
pygame.draw.rect(fenster, ORANGE, [kor(spalte), kor(reihe), kor(1), kor(1)])
Und wenn wir nun die 1-Pixel-Abstände noch integrieren, sieht unser Programm wie folgt aus:
© https://www.python-lernen.de/breakout-spielgegner-mauersteine-zeichnen.htm Seite 422
# Korrekturfaktor berechnen
def kor(zahl):
zahl = zahl * MULTIPLIKATOR
return zahl
# Spielelement zeichnen
def element_zeichnen(spalte,reihe):
pygame.draw.rect(fenster, ORANGE, [kor(spalte)+1, kor(reihe)+1,kor(1)-1,kor(1)-
Und nun lassen wir unsere verschachtelte Liste mit dem Listennamen karte über eine for -
Schleife ausgeben:
# unser Multiplikator
MULTIPLIKATOR = 20
© https://www.python-lernen.de/breakout-spielfeld-ueber-listen.htm Seite 424
# genutzte Farben
ORANGE = ( 255, 140, 0)
SCHWARZ = ( 0, 0, 0)
WEISS = ( 255, 255, 255)
# Hintergrundfarbe Fenster
fenster.fill(WEISS)
# Korrekturfaktor berechnen
def kor(zahl):
zahl = zahl * MULTIPLIKATOR
return zahl
© https://www.python-lernen.de/breakout-spielfeld-ueber-listen.htm Seite 425
return zahl
# Spielelement zeichnen
def element_zeichnen(spalte,reihe):
pygame.draw.rect(fenster, ORANGE, [kor(spalte)+1, kor(reihe)+1,kor(1)-1,kor(1)-
# Schleife Hauptprogramm
while spielaktiv:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
if event.type == pygame.QUIT or event.type == pygame.KEYDOWN and event.key ==
spielaktiv = False
print("Spieler hat beendet")
# Fenster aktualisieren
pygame.display.flip()
# Refresh-Zeiten festlegen
clock.tick(10)
pygame.quit()
Auch für das Zeichnen des Balls erstellen wir eine Funktion mit dem Namen
ball_zeichnen() :
def ball_zeichnen(x,y):
pygame.draw.ellipse(fenster, SCHWARZ, [kor(x), kor(y),kor(1), kor(1)], 0)
Unser Ball benötigt eine Position in unserem Fenster. Dazu erstellen wir 2 Variablen: ball_x
und ball_y . Diese könnten wir zwar per Zufall setzen, der Einfachheit halber setzen wir diese
für den Anfang einfach fix:
# Spielball Variablen
ball_x = 10
ball_y = 23
Der Ball hat noch eine Bewegungsrichtung, die durch 2 Variablen gespeichert wird. Die
verwendeten Variablen sind: ball_x_richtung und ball_y_richtung .
Dabei können diese Variablen positiv wie negativ sein und somit sind alle 4
Bewegungsrichtungen abgedeckt:
1 1 rechts unten
1 -1 rechts oben
-1 1 links unten
-1 -1 links oben
Der Ball muss sich immer schräg bewegen, da bei einer geraden Bewegung das Abprallen vom
Schläger denn Ball exakt in die Richtung zurückwerfen würde, woher er gerade kam (was für
das Spiel nicht besonders sinnvoll wäre).
# Spielball Variablen
ball_x = 10
ball_y = 23
ball_x_richtung = 1
ball_y_richtung = 1
Wer mehr Zufall an der ersten Position haben möchte, versieht einfach der Position ball_x
mit einer zufälligen Zahl zwischen 3 und 16 (ganz an den Rand macht am Anfang auch nicht
wirklich Sinn, daher der Abstand zwischen 0 und 3 und im oberen Bereich):
# Spielball Variablen
ball_x = random.randint(3,16)
ball_y = 23
ball_x_richtung = 1
ball_y_richtung = 1
© https://www.python-lernen.de/breakout-ball-bewegen.htm Seite 427
# Schleife Hauptprogramm
while spielaktiv:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
if event.type == pygame.QUIT or event.type == pygame.KEYDOWN and event.key ==
spielaktiv = False
print("Spieler hat beendet")
# Ball zeichnen
ball_zeichnen(ball_x, ball_y)
Keine Bewegung vom Ball macht natürlich wenig Spaß in einem Spiel. Daher werden wir denn
Ball pro Durchgang über unsere 2 Variablen ball_x_richtung und ball_y_richtung
weiterbewegen.
ball_x += ball_x_richtung
ball_y += ball_y_richtung
# Ball zeichnen
ball_zeichnen(ball_x, ball_y)
Während dem Entwickeln unseres Breakout-Spiels ist diese Bewegung nun ein wenig schnell.
Daher schalten wir auf Zeitlupe um. Unsere Refresh-Zeit ist zu schnell – also schalten wir die
Zeitlupe ein über clock.tick(3) .
Jetzt sieht man schön, wie unser Ball in Zeitlupe am Rand aus dem Bildschirmfenster
verschwindet und zusätzlich eine Spur hinterlässt.
© https://www.python-lernen.de/breakout-ball-bewegen.htm Seite 428
Zur Kontrolle lassen wir uns in der Konsole die aktuelle Position ausgeben:
# Ball zeichnen
ball_zeichnen(ball_x, ball_y)
print("Ballposition X=", ball_x, " / Y = ", ball_y)
Wir sehen in der Konsole, dass ab einer Position von Y=30 der Ball als Nächstes unten
verschwindet. Solange wir noch keinen Schläger haben, soll der Ball im Spiel bleiben. Daher
ändern wir die Y-Richtung des Balls, sobald er die untere Bildschirmkante erreicht.
# Spiellogik
if ball_x >= 19:
ball_x_richtung = -1
ball_x += ball_x_richtung
ball_y += ball_y_richtung
# Ball zeichnen
ball_zeichnen(ball_x, ball_y)
print("Ballposition X=", ball_x, " / Y = ", ball_y)
Aber bevor unser Ball an allen 4 Seiten abprallt, müssen wir alle 4 Seiten kontrollieren. Auch
das kommt an den Punkt innerhalb der Hauptschleife bei der Spiellogik (genaugenommen
Bewegungslogik).
© https://www.python-lernen.de/breakout-ball-bewegen.htm Seite 429
# Schleife Hauptprogramm
while spielaktiv:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
if event.type == pygame.QUIT or event.type == pygame.KEYDOWN and event.key ==
spielaktiv = False
print("Spieler hat beendet")
# Spiellogik
if ball_x <= 0:
ball_x_richtung = 1
if ball_x >= 19:
ball_x_richtung = -1
if ball_y <= 0:
ball_y_richtung *= -1
if ball_y >= 29:
ball_y_richtung *= -1
ball_x += ball_x_richtung
ball_y += ball_y_richtung
# Ball zeichnen
ball_zeichnen(ball_x, ball_y)
print("Ballposition X=", ball_x, " / Y = ", ball_y)
# Fenster aktualisieren
pygame.display.flip()
# Refresh-Zeiten festlegen
clock.tick(3)
pygame.quit()
Nun wollen wir die Felder löschen, wo der Ball sich davor befunden hat. Dazu zeichnen wir
einfach ein weißes Viereck an die alte Position. Würden wir es mit der Trennung zwischen
Spiellogik und Ausgabelogik (Ball zeichnen etc.) nicht genau nehmen, würden wir keine
weiteren Variablen benötigen. Wir wollen aber so nachvollziehbar wie möglich programmieren
und daher trennen wir. Es gibt 2 neue Variablen, in der die alte Position des Balls gespeichert
werden.
# Spielball Variablen
ball_x = random.randint(3,16)
ball_y = 23
ball_x_richtung = 1
ball_y_richtung = 1
ball_x_alt = 0
ball_y_alt = 0
In diesen Variablen werden bei jedem Durchgang die alten Positionen gespeichert, bevor die
Positionen neu gesetzt werden:
© https://www.python-lernen.de/breakout-ball-bewegen.htm Seite 431
ball_x_alt = ball_x
ball_y_alt = ball_y
ball_x += ball_x_richtung
ball_y += ball_y_richtung
# Ball zeichnen
ball_zeichnen(ball_x, ball_y)
Und nun müssen wir nur noch die alte Position löschen. Dazu erstellen wir uns eine Funktion
element_loeschen() . Diese ist ähnlich der Zeichenfunktion für unsere Mauersteine (nur
mit Weiß als Farbe):
def element_loeschen(spalte,reihe):
pygame.draw.rect(fenster, WEISS, [kor(spalte), kor(reihe),kor(1),kor(1)])
Diese Funktion zum Löschen des Inhalts an der alten Bildschirmposition wird vor dem
Zeichnen der neuen Ballposition aufgerufen:
# Ball zeichnen
element_loeschen(ball_x_alt, ball_y_alt)
ball_zeichnen(ball_x, ball_y)
# unser Multiplikator
MULTIPLIKATOR = 20
# genutzte Farben
ORANGE = ( 255, 140, 0)
SCHWARZ = ( 0, 0, 0)
WEISS = ( 255, 255, 255)
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
]
# Spielball Variablen
ball_x = random.randint(3,16)
ball_y = 23
ball_x_richtung = 1
ball_y_richtung = 1
ball_x_alt = 0
ball_y_alt = 0
# Hintergrundfarbe Fenster
fenster.fill(WEISS)
# Korrekturfaktor berechnen
def kor(zahl):
zahl = zahl * MULTIPLIKATOR
return zahl
# Spielelement zeichnen
def element_zeichnen(spalte,reihe):
pygame.draw.rect(fenster, ORANGE, [kor(spalte)+1, kor(reihe)+1,kor(1)-1,kor(1)-
def element_loeschen(spalte,reihe):
pygame.draw.rect(fenster, WEISS, [kor(spalte), kor(reihe),kor(1),kor(1)])
def ball_zeichnen(x,y):
pygame.draw.ellipse(fenster, SCHWARZ, [kor(x), kor(y),kor(1), kor(1)], 0)
naechsterschritt = False
# Schleife Hauptprogramm
while spielaktiv:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
if event.type == pygame.QUIT or event.type == pygame.KEYDOWN and event.key ==
spielaktiv = False
print("Spieler hat beendet")
naechsterschritt = True
print("Nächster Schritt")
# Spiellogik
if ball_x <= 0:
ball_x_richtung = 1
if ball_x >= 19:
ball_x_richtung = -1
if ball_y <= 0:
ball_y_richtung = 1
if ball_y >= 29:
ball_y_richtung = -1
if naechsterschritt == True:
ball_x_alt = ball_x
ball_y_alt = ball_y
ball_x += ball_x_richtung
ball_y += ball_y_richtung
naechsterschritt = False
# Ball zeichnen
element_loeschen(ball_x_alt, ball_y_alt)
ball_zeichnen(ball_x, ball_y)
print("Ballposition X=", ball_x, " / Y = ", ball_y)
# Fenster aktualisieren
pygame.display.flip()
# Refresh-Zeiten festlegen
clock.tick(3)
pygame.quit()
Wir wissen, dass wenn der Ball sich in der Aufwärtsbewegung befindet, die Variable
ball_y_richtung dann den Wert -1 hat. Damit müssen wir also überprüfen, ob das Feld
oberhalb der aktuellen Ballposition einen Mauerstein in dem Listenobjekt karte eingetragen
hat. Ob es das rechte oder links ist, sagt und die Variable ball_x_richtung
im nächsten Schritt trifft der Ball den Mauerstein, der dann verschwinden muss
Schauen wir uns die Berechnung an. Wir haben folgenden 4 Werte:
ball_x
ball_y
ball_x_richtung
© https://www.python-lernen.de/breakout-kollision-ball-mauerstein.htm Seite 435
ball_y_richtung
Nun wird der Ball nach unten abprallen. Wir müssen nur noch den Mauerstein entfernen – und
zwar zweimal:
Im ersten Schritt löschen wir den Bereich auf dem Bildschirm und im weiteren Schritt wird in
dem Listenobjekt das entsprechende Feld mit 0 gefüllt.
Auch diesen Fall sollen wir berücksichtigen. Hier haben wir eine nicht 100 Prozent saubere
Lösung. Einfach selber einmal austüfteln, wie es am besten umgesetzt wird!
© https://www.python-lernen.de/breakout-kollision-ball-mauerstein.htm Seite 436
if ball_x_richtung == 1:
# Ball bewegt sich nach rechts
if karte[ball_y-1][ball_x+1] != 0:
print("trifft Mauerstein rechts oberhalb")
# Mauerstein wird gelöscht von Bildschirm
element_loeschen(ball_x+1, ball_y-1)
# Mauerstein wird gelöscht aus Liste karte
karte[ball_y-1][ball_x+1] = 0
ball_y_richtung = 1
else:
# Ball bewegt sich nach links
if karte[ball_y-1][ball_x-1] != 0:
print("trifft Mauerstein links oberhalb")
# Mauerstein wird gelöscht von Bildschirm
element_loeschen(ball_x-1, ball_y-1)
# Mauerstein wird gelöscht aus Liste karte
karte[ball_y-1][ball_x-1] = 0
ball_y_richtung = 1
Lösung gefunden? Hier ist die Lösung mitsamt der Erweiterung, wenn der Ball auf eine Ecke
von einem Mauerstein auftrifft:
© https://www.python-lernen.de/breakout-kollision-ball-mauerstein.htm Seite 437
Apropos – wenn das wiederholte Drücken der Leertaste lästig wird, kann Pygame eine
Wiederholungsfrequenz mitgeben:
Wie können wir am einfachsten überprüfen, ob diese Siegbedingung eingetreten ist? Wir zählen
in unserer virtuellen Karte die virtuellen Mauersteine (sprich die Einser).
# Siegbedingung erfüllt?
mauersteine = 0
for i in range(len(karte)):
for j in range(len(karte[i])):
if karte[i][j] == 1:
mauersteine = mauersteine + 1
if mauersteine > 1:
print("noch sind Mauersteine ", mauersteine ," da")
else:
# gewonnen, alle Mauersteine sind weg
# Ball wird eingefroren
ball_x_richtung = 0
ball_y_richtung = 0
# Meldung für Sieg
print("Gewonnen - herzlichen Glückwunsch")
Wenn man es genau nimmt, haben wir das aktuelle Level erspielt. Jetzt sollten wir weitere und
schwierigere Levels im Spiel einbauen. Dies kann jeder für sich machen. Anregungen dazu
wäre:
je nach Farbe passieren Dinge (Schläger kleiner oder größer, Ball schneller oder langsamer)
u.s.w.
# unser Multiplikator
MULTIPLIKATOR = 20
clock = pygame.time.Clock()
pygame.key.set_repeat(50,0)
# genutzte Farben
ORANGE = ( 255, 140, 0)
SCHWARZ = ( 0, 0, 0)
WEISS = ( 255, 255, 255)
# Spielball Variablen
ball_x = random.randint(3,16)
ball_y = 23
ball_x_richtung = 1
ball_y_richtung = 1
ball_x_alt = 0
ball_y_alt = 0
# Hintergrundfarbe Fenster
fenster.fill(WEISS)
© https://www.python-lernen.de/breakout-kontrolle-spielende-gewinnen.htm Seite 440
# Korrekturfaktor berechnen
def kor(zahl):
zahl = zahl * MULTIPLIKATOR
return zahl
# Spielelement zeichnen
def element_zeichnen(spalte,reihe):
pygame.draw.rect(fenster, ORANGE, [kor(spalte)+1, kor(reihe)+1,kor(1)-1,kor(1)-
def element_loeschen(spalte,reihe):
pygame.draw.rect(fenster, WEISS, [kor(spalte), kor(reihe),kor(1),kor(1)])
def ball_zeichnen(x,y):
pygame.draw.ellipse(fenster, SCHWARZ, [kor(x), kor(y),kor(1), kor(1)], 0)
naechsterschritt = False
# Schleife Hauptprogramm
while spielaktiv:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
if event.type == pygame.QUIT or event.type == pygame.KEYDOWN and event.key ==
spielaktiv = False
print("Spieler hat beendet")
# Spiellogik
if ball_x <= 0:
ball_x_richtung = 1
if ball_x >= 19:
ball_x_richtung = -1
if ball_y <= 0:
ball_y_richtung = 1
if ball_y >= 29:
ball_y_richtung = -1
# Siegbedingung erfüllt?
mauersteine = 0
for i in range(len(karte)):
for j in range(len(karte[i])):
if karte[i][j] == 1:
mauersteine = mauersteine + 1
if mauersteine > 1:
print("noch sind Mauersteine ", mauersteine ," da")
else:
# gewonnen, alle Mauersteine sind weg
# Ball wird eingefroren
ball_x_richtung = 0
ball_y_richtung = 0
# Meldung für Sieg
print("Gewonnen - herzlichen Glückwunsch")
if naechsterschritt == True:
ball_x_alt = ball_x
ball_y_alt = ball_y
ball_x += ball_x_richtung
ball_y += ball_y_richtung
# naechsterschritt = False
© https://www.python-lernen.de/breakout-kontrolle-spielende-gewinnen.htm Seite 442
# Ball zeichnen
element_loeschen(ball_x_alt, ball_y_alt)
ball_zeichnen(ball_x, ball_y)
if naechsterschritt == True:
print()
print("Richtung X=", ball_x_richtung, " / Y = ", ball_y_richtung)
print("Ballposition X=", ball_x, " / Y = ", ball_y)
# naechsterschritt = False
# Fenster aktualisieren
pygame.display.flip()
# Refresh-Zeiten festlegen
clock.tick(20)
pygame.quit()
exit()
© https://www.python-lernen.de/breakout-spieler-einbauen-bewegen.htm Seite 443
Wir benötigen in unserem Bereich für die Vorgabe der Variablen 3 weitere Variablen:
spielfigur_1_y (für die vertikale (y) Position des Schlägers – diese verändert sich im
ganzen Spiel nicht)
spielfigur_1_x = 10
spielfigur_1_y = 27
spielfigur_1_bewegung = 0
In unserem Bereich „# Spielelement zeichnen“ erstellen wir 2 weitere Funktionen. Als Erstes
wollen wir die Spielfigur zeichnen. Die Funktion nennen wir spielfigur_zeichnen() und
wir übergeben dieser die X-Position.
def spielfigur_zeichnen(x):
pygame.draw.rect(fenster, SCHWARZ,(kor(x), kor(spielfigur_1_y),50,kor(1)))
Für den Eindruck der Bewegung müssen wir die Spielfigur auch wieder vom Bildschirm löschen
können. Die zweite Funktion spielfigur_loeschen(x) zeichnet uns dazu einfach ein
weißes Quadrat.
def spielfigur_loeschen(x):
pygame.draw.rect(fenster, WEISS,(kor(x), kor(spielfigur_1_y),50,kor(1)))
# Ball zeichnen
element_loeschen(ball_x_alt, ball_y_alt)
ball_zeichnen(ball_x, ball_y)
spielfigur_zeichnen(spielfigur_1_x)
Diesen wollen wir natürlich auch bewegen können. Dazu ergänzen wir in der Hauptroutine die
Abfrage der Tastatur in der Hauptschleife. Wir nutzen die Pfeiltaste nach rechts und links für
die Steuerung.
Je nachdem welche Taste der Spieler gedrückt hat, bekommt die Variable
spielfigur_1_bewegung entweder plus 1 oder minus 1 zugewiesen.
# Schleife Hauptprogramm
while spielaktiv:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
if event.type == pygame.QUIT or event.type == pygame.KEYDOWN and event.key ==
spielaktiv = False
print("Spieler hat beendet")
if event.type == pygame.KEYDOWN:
print("Spieler hat Taste gedrückt")
Über unsere Variable können wir nun die Bewegung der Spielerfigur einfach umsetzen. Im
Bereich „# Spiellogik“
# Spiellogik
# Ballbewegung
if ball_x <= 0:
ball_x_richtung = 1
if ball_x >= 19:
ball_x_richtung = -1
if ball_y <= 0:
ball_y_richtung = 1
if ball_y >= 29:
ball_y_richtung = -1
# Spielfigurbewegung
spielfigur_1_x += spielfigur_1_bewegung
Die Spielfigur soll sich auch nur einmal bewegen. Daher setzen wir die Variable nach dem
Zeichnen der Bewegung wieder auf 0:
spielfigur_zeichnen(spielfigur_1_x)
spielfigur_1_bewegung = 0
Schlägerbewegung sauber
Wenn wir nun das Spiel starten, können wir den Schläger bewegen. Es gibt aber noch 2
Schönheitsfehler. Wir zeichnen einen Strich, da wir die alte Schlägerposition nicht löschen. Und
als Zweites prallt unser Ball nicht ab.
© https://www.python-lernen.de/breakout-spieler-einbauen-bewegen.htm Seite 446
Für die alte Schlägerposition benötigen wir eine „neue“ Variable mit dem Namen
spielfigur_1_x_alt . Diese Variable setzen wir bei dem Definitionsbereich am Anfang von
unseren Pythoncode und zusätzlich bevor wir die neue Position des Schlägers berechnen.
# Spielfigurbewegung
spielfigur_1_x_alt = spielfigur_1_x
spielfigur_1_x += spielfigur_1_bewegung
Und nun können wir den Schläger löschen, bevor er an der neuen Position gezeichnet wird.
# Ball zeichnen
element_loeschen(ball_x_alt, ball_y_alt)
ball_zeichnen(ball_x, ball_y)
# Spielerfigur zeichnen
spielfigur_loeschen(spielfigur_1_x_alt)
spielfigur_zeichnen(spielfigur_1_x)
spielfigur_1_bewegung = 0
Soweit so gut. Unser Schläger kann aus dem Fenster verschwinden. Hier müssen wir in der
Spiellogik gegen wirken.
Wir fragen die Position des Schlägers ab und wenn dieser an der rechten oder linken
Fensterrand sich befindet, setzen wir die Bewegung wieder auf 0:
© https://www.python-lernen.de/breakout-spieler-einbauen-bewegen.htm Seite 447
# Spiellogik
# -- Spielfigur darf das Spielfeld links nicht verlassen
if (spielfigur_1_x == 0 and spielfigur_1_bewegung == -1):
spielfigur_1_bewegung = 0
# Ballbewegung
Für den rechten Rand setzen wir nicht bei Position 20, sondern 18 – unser Schläger hat ja eine
Breite und er muss bei 18 stoppen, damit er komplett sichtbar bleibt.
© https://www.python-lernen.de/breakout-kollisionskontrolle-spielerfigur.htm Seite 448
Wenn der Ball auf die gerade Fläche des Schlägers auftrifft, wird dieser im entsprechenden
Winkel abgeschmettert.
Wenn der Ball auf die Kante trifft, fliegt er auf der gleichen Linie zurück.
Wir haben von unserem Schläger die Position spielfigur_1_x und wissen, dass der
Schläger 3 Felder breit ist. Daher können wir die folgenden Berechnungen machen:
Wer nun Spaß hat, kann das Auftreffen auf der Kante noch berücksichtigen, was die
Flugrichtung des Balls beeinflussen sollte. Er sollte dann in der gleichen Richtung
zurückfliegen.
Wenn das Spiel zu schwierig ist, würde das Vergrößern des Schlägers helfen.
© https://www.python-lernen.de/breakout-kollisionskontrolle-spielerfigur.htm Seite 449
© https://www.python-lernen.de/breakout-kontrolle-spielende-verloren.htm Seite 450
Wenn der Ball über die Position 29 kommt, dann ist das Spiel verloren. Bisher hatten wir
folgende Abfrage:
# Ballbewegung
if ball_x <= 0:
ball_x_richtung = 1
if ball_x >= 19:
ball_x_richtung = -1
if ball_y <= 0:
ball_y_richtung = 1
if ball_y >= 29:
ball_y_richtung = -1
Jetzt können wir ganz Brachial hier das Spiel beenden und keine Trennung von Logik und
Ausgabe machen. Also einmal die faule Variante:
# Ballbewegung
if ball_x <= 0:
ball_x_richtung = 1
if ball_x >= 19:
ball_x_richtung = -1
if ball_y <= 0:
ball_y_richtung = 1
if ball_y > 29:
# ball_y_richtung = -1
ball_y_richtung = 0
ball_x_richtung = 0
print("Verloren :(")
Hier kommt dann bei jedem vernünftigen Spiel der Abspann mit Auflistung der Beteiligten und
in welchem Filmstudio gedreht wurde …
Ähm – eigentlich sollten wir mehr als 1 Leben haben. Hier sollte also überprüft werden, ob wir
noch Leben (also weitere Bälle) haben und der nächste Ball dann eingeblendet werden und das
Spiel weitergehen. Darf man machen, kann man machen aber wichtig war bis hierher das
Verständnis vom Ablauf des Programmierens eines Spiels. Alles Weitere ist neben
Fingerübung ein wenig Knobeln und das Kombinieren von jetzt bekannten Elementen.
Hier unser kompletter Code, falls auf dem Weg etwas verloren ging:
# unser Multiplikator
MULTIPLIKATOR = 20
© https://www.python-lernen.de/breakout-kontrolle-spielende-verloren.htm Seite 451
MULTIPLIKATOR = 20
# genutzte Farben
ORANGE = ( 255, 140, 0)
SCHWARZ = ( 0, 0, 0)
WEISS = ( 255, 255, 255)
# Spielball Variablen
ball_x = random.randint(3,16)
ball_y = 23
ball_x_richtung = 1
ball_y_richtung = 1
ball_x_alt = 0
ball_y_alt = 0
# Spielerfigur
spielfigur_1_x = 10
spielfigur_1_y = 28
spielfigur_1_bewegung = 0
# Hintergrundfarbe Fenster
fenster.fill(WEISS)
# Korrekturfaktor berechnen
def kor(zahl):
zahl = zahl * MULTIPLIKATOR
return zahl
# Spielelement zeichnen
def element_zeichnen(spalte,reihe):
pygame.draw.rect(fenster, ORANGE, [kor(spalte)+1, kor(reihe)+1,kor(1)-1,kor(1)-
def element_loeschen(spalte,reihe):
pygame.draw.rect(fenster, WEISS, [kor(spalte), kor(reihe),kor(1),kor(1)])
def ball_zeichnen(x,y):
pygame.draw.ellipse(fenster, SCHWARZ, [kor(x), kor(y),kor(1), kor(1)], 0)
def spielfigur_zeichnen(x):
pygame.draw.rect(fenster, SCHWARZ,(kor(x), kor(spielfigur_1_y),50,kor(1)))
def spielfigur_loeschen(x):
pygame.draw.rect(fenster, WEISS,(kor(x), kor(spielfigur_1_y),50,kor(1)))
naechsterschritt = False
# Schleife Hauptprogramm
while spielaktiv:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
if event.type == pygame.QUIT or event.type == pygame.KEYDOWN and event.key ==
spielaktiv = False
print("Spieler hat beendet")
© https://www.python-lernen.de/breakout-kontrolle-spielende-verloren.htm Seite 453
if event.type == pygame.KEYDOWN:
print("Spieler hat Taste gedrückt")
# Spiellogik
# -- Spielfigur darf das Spielfeld links nicht verlassen
if (spielfigur_1_x == 0 and spielfigur_1_bewegung == -1):
spielfigur_1_bewegung = 0
# Ballbewegung
if ball_x <= 0:
ball_x_richtung = 1
if ball_x >= 19:
ball_x_richtung = -1
if ball_y <= 0:
ball_y_richtung = 1
if ball_y > 29:
# ball_y_richtung = -1
ball_y_richtung = 0
ball_x_richtung = 0
print("Verloren :(")
# Spielfigurbewegung
spielfigur_1_x_alt = spielfigur_1_x
spielfigur_1_x += spielfigur_1_bewegung
else:
if ball_x_richtung == 1:
# Ball bewegt sich nach rechts
if karte[ball_y-1][ball_x+1] != 0:
print("trifft Mauerstein rechts oberhalb")
# Mauerstein wird gelöscht von Bildschirm
element_loeschen(ball_x+1, ball_y-1)
# Mauerstein wird gelöscht aus Liste karte
karte[ball_y-1][ball_x+1] = 0
ball_y_richtung = 1
# trifft auf Ecke, also gleich Richtung zurück
ball_x_richtung = -1
else:
# Ball bewegt sich nach links
if karte[ball_y-1][ball_x-1] != 0:
print("trifft Mauerstein links oberhalb")
# Mauerstein wird gelöscht von Bildschirm
element_loeschen(ball_x-1, ball_y-1)
# Mauerstein wird gelöscht aus Liste karte
karte[ball_y-1][ball_x-1] = 0
ball_y_richtung = 1
# trifft auf Ecke, also gleich Richtung zurück
ball_x_richtung = +1
# Siegbedingung erfüllt?
mauersteine = 0
for i in range(len(karte)):
for j in range(len(karte[i])):
if karte[i][j] == 1:
mauersteine = mauersteine + 1
if mauersteine == 0:
# print("noch sind Mauersteine ", mauersteine ," da")
# else:
# gewonnen, alle Mauersteine sind weg
© https://www.python-lernen.de/breakout-kontrolle-spielende-verloren.htm Seite 455
ball_x_alt = ball_x
ball_y_alt = ball_y
ball_x += ball_x_richtung
ball_y += ball_y_richtung
# Ball zeichnen
element_loeschen(ball_x_alt, ball_y_alt)
ball_zeichnen(ball_x, ball_y)
# Spielerfigur zeichnen
spielfigur_loeschen(spielfigur_1_x_alt)
spielfigur_zeichnen(spielfigur_1_x)
spielfigur_1_bewegung = 0
# Fenster aktualisieren
pygame.display.flip()
# Refresh-Zeiten festlegen
clock.tick(10)
pygame.quit()
exit()
© https://www.python-lernen.de/grundgeruest-fuer-pygame.htm Seite 456
Gehen wir Logisch wie im Flussdiagramm gezeigt nach den einzelnen Bereichen vor.
pygames.locals in den allgemeinen Namensraum „*“ dann direkt die Abfrage KEYDOWN .
Natürlich will man nicht von jeglichem Modul, dass man importiert auch die verwendeten
Namen direkt verfügbar machen, da sonst schnell ein unübersichtliches Chaos entsteht. Für
uns macht es aber Pygame-Programm deutlich übersichtlicher.
Die Auswirkungen an einem Beispiel: somit wird später aus der deutlich längeren Zeile für die
Nutzerabfrage:
Diese Zeile benötigen wir später in diesem Kapitel zum Schritt 4. Hier nur als Beispiel zum
besseren Verständnis!
Sollte der Import des Namespaces nicht erfolgt sein, erhalten wir dann für die optimierte Zeile
einen NameError: „NameError: name 'QUIT' is not defined“.
Jetzt können wir Pygame nutzen – sehen aber noch nichts davon. Also öffnen wir erst einmal
eine Ausgabe, sprich ein Fenster. Für das Fenster benötigen wir Angaben wie die Breite und die
Höhe. Wir benötigen also Konstanten.
Wir benötigen eine Breite und eine Höhe. Bisher haben wir für jede Variable und Konstante eine
extra Zeile in Python erstellt. Das werden wir nun für logisch zusammengehörige Variablen
nicht mehr machen und Python erlaubt auch sehr einfach die Wertzuweisung in einer Zeile.
Für die Breite nutzen wir ein großes „W“ und für die Höhe ein großes „H“. Das große H ist jedem
sofort klar. Hier kommt das „H“ aus dem Wort „Höhe“. Hier haben wir den Zufall, dass das
© https://www.python-lernen.de/grundgeruest-fuer-pygame.htm Seite 458
Bei der Breite kommt das große „W“ von dem Anfangsbuchstaben des englischen Worts
„widht“. Da es üblich ist, verwenden wir diese 2 Werte mit dieser Bezeichnung und als
Konstante:
# Variablen/KONSTANTEN setzen
W, H = 800, 600
In diesem Bereich sind auch im Programm genutzte Farben gut untergebracht. Für die
Fensterfarbe benötigen wir zum Beispiel später auch eine Hintergrundfarbe. Wir setzen hier die
deutschen Namen als Konstanten. Wer englische Bezeichnungen bevorzugt, kann natürlich
auch mit englischen Namen arbeiten:
# Variablen/KONSTANTEN setzen
W, H = 800, 600
# Farben setzen
SCHWARZ = ( 0, 0, 0)
WEISS = ( 255, 255, 255)
Den Bereich für die Variablen erweitern wir nach und nach, wenn wir die entsprechenden Werte
in unserem Programm benötigen.
# Variablen/KONSTANTEN setzen
W, H = 800, 600
SCHWARZ = ( 0, 0, 0)
WEISS = ( 255, 255, 255)
Als letzte Angabe wollen wir noch die Uhr verfügbar machen, damit wir später die Häufigkeit
© https://www.python-lernen.de/grundgeruest-fuer-pygame.htm Seite 459
# Variablen/KONSTANTEN setzen
W, H = 800, 600
SCHWARZ = ( 0, 0, 0)
WEISS = ( 255, 255, 255)
Es wird für einen Bruchteil einer Sekunde ein Fenster angezeigt und schon ist unser Programm
wieder beendet. Wir benötigen also ein Hauptprogramm, das länger läuft. Das wird im vierten
Bereich umgesetzt.
Wenn wir eine Endlosschleife erstellen wollen, können wir auch direkt while True:
verwenden. Wird das Programm durch die Escape-Taste oder durch das entsprechende im
Fensterkopf beendet, können wir direkt das Programm über pygame.quit() beenden.
Innerhalb unseres Hauptprogramms kommt die Abfrage für die Nutzeraktion. Diese haben wir
uns bereits beim Schritt 1 angesehen. Somit haben wir folgenden Code:
© https://www.python-lernen.de/grundgeruest-fuer-pygame.htm Seite 460
# Variablen/KONSTANTEN setzen
W, H = 800, 600
SCHWARZ = ( 0, 0, 0)
WEISS = ( 255, 255, 255)
# Schleife Hauptprogramm
while True:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
# Beenden bei [ESC] oder [X]
if event.type==QUIT or (event.type==KEYDOWN and event.key==K_ESCAPE):
pygame.quit()
# Spiellogik
# Spielfeld löschen
fenster.fill(HGFARBE)
# Spielfeld/figuren zeichnen
# Fenster aktualisieren
pygame.display.flip()
clock.tick(FPS)
Bei den Refresh-Zeiten bei clock.tick(FPS) muss die Konstante oben im Programm in
unseren Bereich von Schritt 2 noch gesetzt werden.
© https://www.python-lernen.de/grundgeruest-fuer-pygame.htm Seite 461
# Variablen/KONSTANTEN setzen
W, H = 800, 600
FPS = 60
SCHWARZ = ( 0, 0, 0)
WEISS = ( 255, 255, 255)
# Schleife Hauptprogramm
while True:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
# Beenden bei [ESC] oder [X]
if event.type==QUIT or (event.type==KEYDOWN and event.key==K_ESCAPE):
pygame.quit()
# Spiellogik
# Spielfeld löschen
fenster.fill(WEISS)
# Spielfeld/figuren zeichnen
# Fenster aktualisieren
pygame.display.flip()
clock.tick(FPS)
© https://www.python-lernen.de/bilder-grafiken-anzeigen-pygame.htm Seite 462
Grundlagen Grafiken/Bilder
Bildformate
Bei Bildern gibt es verschiedene Bildformate. Uns stehen in Python die Bildformate „.jpg“, „.png“
und „.gif“ zur Verfügung.
Der Nullpunkt ist immer oben links wie in der folgenden Grafik eingezeichnet. Von hier aus
werden nach rechts die X-Werte und nach unten die y-Werte größer. Wichtig in diesem
Zusammenhang ist die gesamte Breite und die Höhe. Hier kann man sich gleich die englischen
Begriffe für Breite = width und Höhe = height einprägen.
Denn spätestens, wenn unsere Grafik am rechten Fensterrand nicht einfach verschwinden soll,
sondern dort abprallen, benötigen wir die Breite für Berechnungen. Wir können über die
Position unserer Grafik auf den Nullpunkt zugreifen aber erst mit Nullpunkt plus der Breite bzw.
Höhe können wir berechnen, ob die Grafik den Fensterrand rechts bzw. unten berührt.
© https://www.python-lernen.de/bilder-grafiken-anzeigen-pygame.htm Seite 463
Im ersten Schritt wollen wir eine Grafik laden. Dabei wird die Grafik noch nicht im Fenster
platziert, sprich sie ist noch nicht sichtbar. Diese muss erst erfolgreich geladen werden. Wir
vergeben eine „Variable“, auf die wir dann zugreifen können.
spielerfigur = pygame.image.load("biene.png")
Die hier verwendete Grafik der Biene kann über die URL: https://www.python-
lernen.de/bilder/biene.png zum Spielen und Testen heruntergeladen werden. Dazu einfach auf
die Grafik mit der rechten Maustaste klicken und „speichern unter“ wählen.
Lässt man sich die „Variable“ über print(spielerfigur) ausgeben, erhalten wir als
Rückgabe: <Surface(100x99x32 SW)>
WICHTIG! Unsere Grafik „biene.png“ befindet sich im gleichen Verzeichnis wie unser Python-
Programm. Sonst kann Python die Grafik nicht finden. Wer mehr Ordnung halten möchte, kann
auch alle Grafiken in ein Unterverzeichnis packen und dann darauf zugreifen. Dazu erstellen wir
im Verzeichnis, in dem unser Python-Programm liegt das Unterverzeichnis „bilder“ und packen
dort alle verwendeten Grafiken hinein. Dann ändert sich unser Python-Code entsprechend:
spielerfigur = pygame.image.load("bilder/biene.png")
Sollte das Bild sich nicht im Verzeichnis befinden oder ein Tippfehler im Dateinamen (Groß-
Kleinschreibung ist wichtig, Dateiende ist wichtig!) sich eingeschlichen haben, erhalten wir eine
Fehlermeldung in folgender Form:
Jetzt kann es durchaus sein, dass uns die Bildgrößen der Grafiken nicht bekannt sind. Wir
können mit Pygame die Größen ermitteln und ausgeben lassen. Um die Größen zu ermitteln,
nutzen wir die Anweisung get_rect() .
spielerfigur = pygame.image.load("bilder/biene.png")
bildgroessen = spielerfigur.get_rect()
die Mitte der Breite (was der Hälfte der Breite entspricht) über bildgroessen.center[0]
Die Werte können wir uns einfach einmal zur Kontrolle ausgeben lassen:
spielerfigur = pygame.image.load("bilder/biene.png")
bildgroessen = spielerfigur.get_rect()
print(bildgroessen)
print(bildgroessen.center[0])
print(bildgroessen.center[1])
print(bildgroessen.width)
print(bildgroessen.height)
# Variablen/KONSTANTEN setzen
W, H = 800, 600
FPS = 60
SCHWARZ = ( 0, 0, 0)
WEISS = ( 255, 255, 255)
spielaktiv = True
# Schleife Hauptprogramm
while spielaktiv:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
# Beenden bei [ESC] oder [X]
if event.type==QUIT or (event.type==KEYDOWN and event.key==K_ESCAPE):
spielaktiv = False
# Spiellogik
# Spielfeld löschen
fenster.fill(WEISS)
# Spielfeld/figuren zeichnen
# Fenster aktualisieren
pygame.display.flip()
clock.tick(FPS)
© https://www.python-lernen.de/bilder-grafiken-anzeigen-pygame.htm Seite 465
Unsere Grafik laden wir vor der Hauptschleife vor dem „# Definieren und Öffnen eines neuen
Fensters“.
# Variablen/KONSTANTEN setzen
W, H = 800, 600
FPS = 60
SCHWARZ = ( 0, 0, 0)
WEISS = ( 255, 255, 255)
spielaktiv = True
spielerfigur = pygame.image.load("bilder/biene.png")
bildgroessen = spielerfigur.get_rect()
print(bildgroessen)
print(bildgroessen.center[0])
print(bildgroessen.center[1])
print(bildgroessen.width)
print(bildgroessen.height)
Lassen wir unser Python-Programm ausführen, erhalten wir in der Konsole folgende Ausgabe
für die Größen:
Jetzt können wir in unserer Hauptroutine (Schleife Hauptprogramm) die Grafik ausgeben
lassen.
# Spielfeld/figuren zeichnen
fenster.blit(spielerfigur, (200, 100))
Unsere Biene als Grafik erscheint nun an der Position x=200 und y=100 in unserem Fenster:
Klugscheißermodus zu blit(): wer sich über die merkwürdige Anweisung blit() wundert.
Diese kommt aus der Bezeichnung „Bit blit“ – auch als BITBLT „allgemein“ bekannt ;). Und das
BLT steht dann für „BLock Transfer“. Es wird im Vorfeld alles auf einer Bitmap verrechnet
bevor es auf einen Schlag angezeigt wird. Dadurch wird Rechenleistung gespart.
Wenn wir nun die Hintergrundfarbe des Fensters ändern, sehen wir die quadratische Struktur
unseres Bildes:
# Variablen/KONSTANTEN setzen
W, H = 800, 600
FPS = 60
SCHWARZ = ( 0, 0, 0)
WEISS = ( 255, 255, 255)
GRAU = ( 155, 155, 155)
# Spielfeld löschen
fenster.fill(GRAU)
Wir wollen auf jeden Fall, dass die Hintergrundfarbe die Kontur der Biene „umfließt“:
Dazu ist wichtig zu wissen, dass wir bei den Grafikformaten PNG und GIF einen transparenten
Bereich definieren können. Hier spricht man vom Alphakanal.
Und nun müssen wir beim Laden der Grafik noch mitgeben, dass dieser Alphakanal genutzt
werden soll.
# Variablen/KONSTANTEN setzen
W, H = 800, 600
FPS = 60
SCHWARZ = ( 0, 0, 0)
WEISS = ( 255, 255, 255)
GRAU = ( 155, 155, 155)
spielaktiv = True
spielerfigur = pygame.image.load("bilder/biene.png").convert_alpha()
bildgroessen = spielerfigur.get_rect()
print(bildgroessen)
print(bildgroessen.center[0])
print(bildgroessen.center[1])
print(bildgroessen.width)
print(bildgroessen.height)
# Schleife Hauptprogramm
while spielaktiv:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
# Beenden bei [ESC] oder [X]
if event.type==QUIT or (event.type==KEYDOWN and event.key==K_ESCAPE):
spielaktiv = False
# Spiellogik
# Spielfeld löschen
fenster.fill(GRAU)
# Spielfeld/figuren zeichnen
fenster.blit(spielerfigur, (200, 100))
# Fenster aktualisieren
pygame.display.flip()
clock.tick(FPS)
In den folgenden Kapiteln schauen wir uns an, wie man Grafiken bewegen, rotieren, skalieren
und Animieren kann.
© https://www.python-lernen.de/grafiken-rotieren.htm Seite 468
Die beiden Grafiken können über die jeweilige URL heruntergeladen werden oder einfach mit
der Maus auf die Grafik klicken und „speichern unter“ wählen:
https://www.python-lernen.de/bilder/propeller.png
https://www.python-lernen.de/bilder/propellerflieger.png
Zum Einbauen der 2 Grafiken nutzen wir unseren bisherigen Code aus dem letzten Kapitel:
© https://www.python-lernen.de/grafiken-rotieren.htm Seite 469
# Variablen/KONSTANTEN setzen
W, H = 800, 600
FPS = 60
SCHWARZ = ( 0, 0, 0)
WEISS = ( 255, 255, 255)
GRAU = ( 155, 155, 155)
spielaktiv = True
spielerfigur = pygame.image.load("bilder/biene.png").convert_alpha()
bildgroessen = spielerfigur.get_rect()
# Schleife Hauptprogramm
while spielaktiv:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
# Beenden bei [ESC] oder [X]
if event.type==QUIT or (event.type==KEYDOWN and event.key==K_ESCAPE):
spielaktiv = False
# Spiellogik
# Spielfeld löschen
fenster.fill(GRAU)
# Spielfeld/figuren zeichnen
fenster.blit(spielerfigur, (200, 100))
# Fenster aktualisieren
pygame.display.flip()
clock.tick(FPS)
Anstelle unserer Biene aus dem Kapitel Space Invaders war gestern – Varroa Invaders
importieren wir nun unsere 2 Grafiken und vergeben die Namen propeller und
flugzeugrumpf :
propeller = pygame.image.load("bilder/propeller.png")
flugzeugrumpf = pygame.image.load("bilder/propellerflieger.png")
# Spielfeld/figuren zeichnen
fenster.blit(flugzeugrumpf, (0, 0))
fenster.blit(propeller, (0, 0))
© https://www.python-lernen.de/grafiken-rotieren.htm Seite 470
Allerdings haben wir noch einen grauen Himmel – wir sind aber Schönwetterflieger und wollen
deshalb einen schönen blauen Himmel!
Also die Hintergrundfarbe auf Hellblau ändern. Meine benutzte Farbe hat den Wert:
HIMMELBLAU = (120, 210, 255)
# Variablen/KONSTANTEN setzen
W, H = 800, 600
FPS = 60
SCHWARZ = ( 0, 0, 0)
WEISS = (255, 255, 255)
GRAU = (155, 155, 155)
HIMMELBLAU = (120, 210, 255)
spielaktiv = True
propeller = pygame.image.load("bilder/propeller.png")
flugzeugrumpf = pygame.image.load("bilder/propellerflieger.png")
# Schleife Hauptprogramm
while spielaktiv:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
# Beenden bei [ESC] oder [X]
if event.type==QUIT or (event.type==KEYDOWN and event.key==K_ESCAPE):
spielaktiv = False
# Spiellogik
# Spielfeld löschen
fenster.fill(HIMMELBLAU)
# Spielfeld/figuren zeichnen
fenster.blit(flugzeugrumpf, (0, 0))
fenster.blit(propeller, (0, 0))
# Fenster aktualisieren
pygame.display.flip()
clock.tick(FPS)
# Spielfeld/figuren zeichnen
fenster.blit(flugzeugrumpf, (20, 30))
fenster.blit(propeller, (118, 32))
Bei dem Rotationsbefehl gibt man in der Klammer das zu rotierende Ursprungsbild an und den
Winkel (ohne Größenangabe).
Wir erzeugen eine zweite Grafik, um das Verständnis bei Rotationen schnell zu bekommen:
Nach dem Platzieren passt da allerdings etwas nicht bzw. ist nicht wie erwartet:
# Spielfeld/figuren zeichnen
fenster.blit(flugzeugrumpf, (20, 30))
fenster.blit(propeller, (118, 32))
fenster.blit(propeller2, (118, 32))
Unser Propeller rotiert nicht wie gewünscht. Der rote Punkt (der aus didaktischen Gründen rot
ist und sofort sichtbar) ist der Mittelpunkt unseres Propellers. Nach unserer ersten Rotation
scheint der Propeller vom Flieger abzufallen. Nichts was man bei einem gemütlichen Flug
gerne hätte.
Die Rotation hat nicht um das Zentrum unserer Grafik stattgefunden. Zum Testen erstellen wir
uns eine Funktion mit dem Namen rotieren_zentrieren() , der wir neben der X und Y-
Angabe noch unser Bild und den Rotationsgrad angeben:
Im Hauptprogramm beim Spiel erweitern wir um den Aufruf der Funktion rotieren()
anstelle von fenster.blit(propeller2, (118, 32))
© https://www.python-lernen.de/grafiken-rotieren.htm Seite 473
# Spielfeld/figuren zeichnen
fenster.blit(flugzeugrumpf, (20, 30))
fenster.blit(propeller, (118, 32))
# fenster.blit(propeller2, (118, 32))
rotieren(118, 32, propeller, 20)
Damit wir besser sehen, in welchem Bereich die Berechnung erfolgt, zeichnen wir ein rotes
Viereck um die aktuelle Stellung des Propellers. Dies geschieht in unserer neuen Funktion:
Wenn wir die Propeller in der Grundstellung ohne Rotation mit Viereck zeichnen lassen und
dann rotiert, sieht man schön das nach unten rechts wachsendem Quadrat:
Für die Rotation wird also der Nullpunkt links oben gesetzt – daher „wächst“ das Quadrat nach
rechts und unten und unser Propeller eiert durch die Gegend.
# Spiellogik
if gradzahl <= 359:
gradzahl += 5
else:
gradzahl = 0
Zur Erinnerung: Unsere Rotation erfolgt gegen den Uhrzeigersinn. Wollte man nun eine
Rotation im Uhrzeigersinn, würde man von 359 nach 0 zählen lassen.
# Spielfeld/figuren zeichnen
fenster.blit(flugzeugrumpf, (20, 30))
rotieren(118, 32, propeller, gradzahl)
Wir wollen also, dass unsere Grafik um den Mittelpunkt rotiert – bei unserem Propeller sitzt
dieser exakt auf dem roten Punkt.
Daher erstellen wir uns im nächsten Schritt eine Funktion mit dem Namen
rotieren_zentrieren() .
Auch dieser Funktion wird neben der X und Y-Angabe noch unser Bild und den Rotationsgrad
mitgegeben:
# Ausgabe
fenster.blit(rotiert, (x - groesse.center[0],y - groesse.center[1]))
Wenn man sich den Programmcode anschaut, sieht man den Trick. Es wird nach der Rotation
die Größen der Grafik bestimmt und dann diese mittig ausgegeben. Über center[0] und
center[1] haben wir den Mittelpunkt.
Man sieht schön anhand des Vierecks der alten Rotationsfunktion, dass die Rotation exakt auf
dem Nullpunkt der x- und y-Angabe sitzt. Diese verschieben wir später noch.
Jetzt lassen wir uns einfach zur Kontrolle noch ein Viereck ausgeben:
© https://www.python-lernen.de/grafiken-rotieren.htm Seite 475
# Ausgabe
fenster.blit(rotiert, (x - groesse.center[0],y - groesse.center[1]))
Wir wissen, dass unser Propeller eine Breite von 100 und eine Höhe von 63 hat. Also geben wir
die beim Aufruf die Hälfe jeweils mit (die Zahl 118 und 32 stammt aus dem ursprünglichen
Platzieren des Flugzeugrumpfs):
Somit haben wir eine saubere Rotation um den Mittelpunkt (was man dann doch öfters
benötigt) und haben alle Möglichkeiten von Rotationen von Grafiken über Pygame und Python
kennengelernt.
# Variablen/KONSTANTEN setzen
W, H = 800, 600
W_HALBE = W / 2
H_HALBE = H / 2
FPS = 60
SCHWARZ = ( 0, 0, 0)
WEISS = (255, 255, 255)
GRAU = (155, 155, 155)
HIMMELBLAU = (120, 210, 255)
spielaktiv = True
gradzahl = 0
propeller = pygame.image.load("bilder/propeller.png")
flugzeugrumpf = pygame.image.load("bilder/propellerflieger.png")
# Ausgabe
fenster.blit(rotiert, (x - groesse.center[0],y - groesse.center[1]))
# Schleife Hauptprogramm
while spielaktiv:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
# Beenden bei [ESC] oder [X]
if event.type==QUIT or (event.type==KEYDOWN and event.key==K_ESCAPE):
spielaktiv = False
# Spiellogik
if gradzahl <= 359:
gradzahl += 5
else:
gradzahl = 0
# Spielfeld löschen
fenster.fill(HIMMELBLAU)
# Spielfeld/figuren zeichnen
fenster.blit(flugzeugrumpf, (20, 30))
# rotieren(118, 32, propeller, gradzahl)
rotieren_zentrieren(118+50, 32+31, propeller, gradzahl)
# Fenster aktualisieren
pygame.display.flip()
clock.tick(FPS)
© https://www.python-lernen.de/grafiken-rotieren.htm Seite 477
© https://www.python-lernen.de/grafiken-skalieren.htm Seite 478
Und wieder nehmen wir unser Grundgerüst, und setzen dort unsere Grafik ein.
© https://www.python-lernen.de/grafiken-skalieren.htm Seite 479
# Variablen/KONSTANTEN setzen
W, H = 800, 600
FPS = 30
SCHWARZ = ( 0, 0, 0)
WEISS = ( 255, 255, 255)
GRAU = ( 155, 155, 155)
spielaktiv = True
spielerfigur = pygame.image.load("bilder/biene-gr.png")
bildgroessen = spielerfigur.get_rect()
print(bildgroessen)
print(bildgroessen.center[0])
print(bildgroessen.center[1])
print(bildgroessen.width)
print(bildgroessen.height)
# Schleife Hauptprogramm
while spielaktiv:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
# Beenden bei [ESC] oder [X]
if event.type==QUIT or (event.type==KEYDOWN and event.key==K_ESCAPE):
spielaktiv = False
# Spiellogik
# Spielfeld löschen
fenster.fill(GRAU)
# Spielfeld/figuren zeichnen
fenster.blit(spielerfigur, (200, 100))
# Fenster aktualisieren
pygame.display.flip()
clock.tick(FPS)
Bauen wir nun unsere 3 Bienen fix ein. Effektiv müssen wir diese nur einmal laden und erstellen
dann durch transform.scale() uns die gewünschte Anzahl von Grafiken in der
gewünschte Größe:
© https://www.python-lernen.de/grafiken-skalieren.htm Seite 480
# Variablen/KONSTANTEN setzen
W, H = 800, 600
FPS = 60
SCHWARZ = ( 0, 0, 0)
WEISS = ( 255, 255, 255)
GRAU = ( 155, 155, 155)
spielaktiv = True
spielerfigur = pygame.image.load("bilder/biene-gr.png")
# Schleife Hauptprogramm
while spielaktiv:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
# Beenden bei [ESC] oder [X]
if event.type==QUIT or (event.type==KEYDOWN and event.key==K_ESCAPE):
spielaktiv = False
# Spiellogik
# Spielfeld löschen
fenster.fill(GRAU)
# Spielfeld/figuren zeichnen
bienen_klein = pygame.transform.scale(spielerfigur, (150,150))
bienen_mittel = pygame.transform.scale(spielerfigur, (250,250))
bienen_gross = pygame.transform.scale(spielerfigur, (350,350))
fenster.blit(bienen_klein, (500, 60))
fenster.blit(bienen_mittel, (340, 190))
fenster.blit(bienen_gross, (80, 60))
# Fenster aktualisieren
pygame.display.flip()
clock.tick(FPS)
Wenn wir nun noch mit den Größen und der Zeit spielen, entsteht ein interessanter Effekt. Wir
lassen die Größen leicht variieren.
Dazu setzen wir bei der Definition der Variablen der Startwert skalierung = 0 und
verändernden Faktor über skalierungswert = 1 .
In der Spiellogik verändern wir den Wert und fragen ab, ob er über 6 geht und verändern die
Richtung:
# Spiellogik
skalierung += skalierungswert
Und beim Zeichnen der Spielfiguren geben wir den Wert bei 2 Grafiken mit Plus und bei einer
Grafik mit Minus mit. Somit bewegen sich die Bienen zueinander.
# Spielfeld/figuren zeichnen
bienen_klein = pygame.transform.scale(spielerfigur, (150+skalierung,150+skalierung))
bienen_mittel = pygame.transform.scale(spielerfigur, (250-skalierung,250-skalierung))
bienen_gross = pygame.transform.scale(spielerfigur, (350+skalierung,350+skalierung))
fenster.blit(bienen_klein, (500, 60))
fenster.blit(bienen_mittel, (340, 190))
fenster.blit(bienen_gross, (80, 60))
# Variablen/KONSTANTEN setzen
W, H = 800, 600
FPS = 30
SCHWARZ = ( 0, 0, 0)
WEISS = ( 255, 255, 255)
GRAU = ( 155, 155, 155)
spielaktiv = True
skalierung = 0
skalierungswert = 1
spielerfigur = pygame.image.load("bilder/biene-gr.png")
# Schleife Hauptprogramm
while spielaktiv:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
# Beenden bei [ESC] oder [X]
if event.type==QUIT or (event.type==KEYDOWN and event.key==K_ESCAPE):
spielaktiv = False
# Spiellogik
skalierung += skalierungswert
# Spielfeld löschen
fenster.fill(GRAU)
# Spielfeld/figuren zeichnen
bienen_klein = pygame.transform.scale(spielerfigur, (150+skalierung,150+skalierung))
bienen_mittel = pygame.transform.scale(spielerfigur, (250-skalierung,250-skalierung))
bienen_gross = pygame.transform.scale(spielerfigur, (350+skalierung,350+skalierung))
fenster.blit(bienen_klein, (500, 60))
fenster.blit(bienen_mittel, (340, 190))
fenster.blit(bienen_gross, (80, 60))
# Fenster aktualisieren
pygame.display.flip()
clock.tick(FPS)
Und als Ergebnis erhalten wir folgende Animation (in Python dann sehr viel flüssiger als hier):
© https://www.python-lernen.de/grafiken-skalieren.htm Seite 483
Jetzt wäre noch schön, wenn die Flügel schlagen würden. Die Animation der Flügel wird das
Thema unseres nächsten Kapitels sein.
© https://www.python-lernen.de/animationen-erstellen.htm Seite 484
Dieses Sprite wird in mehreren Varianten vorgehalten und wird dann je nach Zustand
angezeigt. So können Bewegungen simuliert werden. Da unser Auge träge ist, müssen auch
nicht alle Zwischenschritte eine Bewegung angezeigt werden.
Für das Beispiel mit dem Flügelschlag der Biene reichen uns 6 Bilder, die sich abwechseln:
Die einzelnen Stadien der Bewegung kann man in einer Grafikdatei abspeichern und jeweils nur
einen Ausschnitt davon anzeigen. Sind also mehrere Bewegungsschritte in einer Datei
abgespeichert, spricht man von Sprite-Sheet (kennt man aus dem Englischen mit dem Begriff
„data sheet“ für Datenblatt – anstelle von einzelnen Daten haben wir eben einzelne Grafiken in
unserem Sprite-Sheet).
Wie können wir nun mit Python und Pygame daraus eine Animation erstellen? Sehr einfach und
sogar auf 2 Wege, die hier beide gezeigt werden sollen.
https://www.python-lernen.de/bilder/biene-r-001.png
https://www.python-lernen.de/bilder/biene-r-002.png
https://www.python-lernen.de/bilder/biene-r-003.png
https://www.python-lernen.de/bilder/biene-r-004.png
https://www.python-lernen.de/bilder/biene-r-005.png
https://www.python-lernen.de/bilder/biene-r-006.png
Diese Grafiken speichern wir im Unterordner „bilder“ und laden diese über Pygame in eine
Liste. Dadurch können wir dann im Spiel gezielt für die Animation die einzelnen Stadien der
© https://www.python-lernen.de/animationen-erstellen.htm Seite 485
biene = ['','','','','','']
biene = ['','','','','','']
biene[0] = pygame.image.load("bilder/biene-r-001.png")
biene[1] = pygame.image.load("bilder/biene-r-002.png")
biene[2] = pygame.image.load("bilder/biene-r-003.png")
biene[3] = pygame.image.load("bilder/biene-r-004.png")
biene[4] = pygame.image.load("bilder/biene-r-005.png")
biene[5] = pygame.image.load("bilder/biene-r-006.png")
Das ginge zwar als Code galanter, aber so ist es am einfachsten zu verstehen, was hier
passiert.
Jetzt brauchen wir einen Status, welche Grafik aktuell angezeigt werden soll. Wir definieren
eine Variable mit dem Namen frame = 0 .
Und innerhalb unserer Hauptschleife laufen wir durch alle vorhandenen Framenummer durch
und beginnen wieder bei 0, wenn wir den letzten erreicht haben. Noch schöner wäre, wenn wir
die Frames einfach rückwärts wieder durchgehen würden.
frame += 1
if frame > 5:
frame = 0
Und nun müssen wir nur noch unsere Biene mit dem entsprechenden Index (sprich Frame)
zeichnen:
Unsere Biene ist nun wild am Flügelschlagen (man will ja im Leben vorwärtskommen).
# Variablen/KONSTANTEN setzen
W, H = 800, 600
FPS = 30
SCHWARZ = ( 0, 0, 0)
WEISS = ( 255, 255, 255)
© https://www.python-lernen.de/animationen-erstellen.htm Seite 486
biene = ['','','','','','']
biene[0] = pygame.image.load("bilder/biene-r-001.png")
biene[1] = pygame.image.load("bilder/biene-r-002.png")
biene[2] = pygame.image.load("bilder/biene-r-003.png")
biene[3] = pygame.image.load("bilder/biene-r-004.png")
biene[4] = pygame.image.load("bilder/biene-r-005.png")
biene[5] = pygame.image.load("bilder/biene-r-006.png")
frame = 0
# Schleife Hauptprogramm
while spielaktiv:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
# Beenden bei [ESC] oder [X]
if event.type==QUIT or (event.type==KEYDOWN and event.key==K_ESCAPE):
spielaktiv = False
# Spiellogik
# Spielfeld löschen
fenster.fill(GRAU)
# Spielfeld/figuren zeichnen
frame += 1
if frame > 5:
frame = 0
# Fenster aktualisieren
pygame.display.flip()
clock.tick(FPS)
Falls man sich die Bewegung langsam ansehen möchten, kann man einfach den FPS-Wert
umstellen auf: FPS = 1
Zum besseren verdeutlichen ist um jedes Stadium ein bunter Rahmen gezogen:
© https://www.python-lernen.de/animationen-erstellen.htm Seite 487
Jedes Bild unserer Bienen ist 100 Pixel breit und 100 Pixel hoch.
Somit können wir für jedes Stadium exakt die Angaben machen, bei welchem X- und Y-Wert
das entsprechende Teilstück des Bildes anfängt und auch aufhört.
Wir erhalten also 4 Werte. Wollen wir beispielsweise das dritte Stadium nutzen (die grün
umrandete Biene), dann können wir dies direkt über die Werte (201, 0, 301, 100) ansprechen.
Bei der Anweisung blit() gibt es die Möglichkeit, dass nur ein Teilbereich des gesamten
Bildes (also ein Ausschnitt) angezeigt wird. Dieser Ausschnitt wird festgelegt über den
Startpunkt, also den oberen X- und Y-Wert und zusätzlich die Breite und die Höhe. Als Beispiel:
der Teilausschnitt mit dem grünen Rahmen kann somit über die Angabe (201, 0, 100,100)
ausgewählt werden.
Unser Code:
Unser Code unterscheidet sich also nicht so wesentlich wie in der ersten Vorgehensweise. Wir
bauen im Folgenden nochmals das gleiche Beispiel wie schon in der Vorgehensweise mit den
Einzelgrafiken – jetzt aber mit unserer Grafik als Sprite-Sheet.
https://www.python-lernen.de/bilder/biene-sprite-sheet.png
(oder einfach auf die Grafik mit der rechten Maustaste klicken und "speichern unter" wählen)
biene = pygame.image.load("bilder/biene-sprite-sheet.png")
Und hinterlegen die Koordinaten unter bereich : X- und Y-Wert, wo der Bereich beginnt und
die letzten beiden Zahlen sind die Breite und die Höhe (was in allen Fällen 100 Pixel sind).
bereich = ['','','','','','']
bereich[0] = (0,0,100,100)
bereich[1] = (101,0,100,100)
bereich[2] = (202,0,100,100)
bereich[3] = (303,0,100,100)
bereich[4] = (404,0,100,100)
bereich[5] = (505,0,100,100)
Innerhalb unserer Hauptschleife ändern wir in jedem Durchgang die Frame-Nummer und
lassen uns den durch den Bereich festgelegten Teilausschnitt ausgeben:
# Spielfeld/figuren zeichnen
frame += 1
if frame > 5:
frame = 0
print(frame, bereich[frame])
# Variablen/KONSTANTEN setzen
W, H = 800, 600
FPS = 2
SCHWARZ = ( 0, 0, 0)
WEISS = ( 255, 255, 255)
GRAU = ( 155, 155, 155)
spielaktiv = True
biene = pygame.image.load("bilder/biene-sprite-sheet.png")
bereich = ['','','','','','']
© https://www.python-lernen.de/animationen-erstellen.htm Seite 489
bereich[0] = (0,0,100,100)
bereich[1] = (101,0,100,100)
bereich[2] = (202,0,100,100)
bereich[3] = (302,0,100,100)
bereich[4] = (402,0,100,100)
bereich[5] = (504,0,100,100)
print(bereich)
frame = 0
# Schleife Hauptprogramm
while spielaktiv:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
# Beenden bei [ESC] oder [X]
if event.type==QUIT or (event.type==KEYDOWN and event.key==K_ESCAPE):
spielaktiv = False
# Spiellogik
# Spielfeld löschen
fenster.fill(WEISS)
# Spielfeld/figuren zeichnen
frame += 1
if frame > 5:
frame = 0
print(frame, bereich[frame])
# Fenster aktualisieren
pygame.display.flip()
clock.tick(FPS)
PS: die Sprünge bei den verschiedenen Bereichen kommen daher, dass die Grundgrafik nicht
sauber ist – sprich nicht überall 100 Pixel Breite pro Biene haben (die Grafik mache ich bei
Gelegenheit noch sauber). Wichtig ist hier erst einmal das Verständnis für die Vorgehensweise.
https://en.wikipedia.org/wiki/Eadweard_Muybridge#/media/File:The_Horse_in_Motion_high_res.jpg
Was wollen wir in Python als Übungsspiel programmieren? Ähnlich dem Spielprinzip wie bei
Space Invaders greifen wir in unserem Spiel nicht nach den Sternen, sondern stellen und einem
realen Problem, mit dem jeder Imker kämpft: Der Varroamilbe – dieser Schädling ist die Furcht
jedes Imkers. Wenn wir es uns einen ähnlichen Schädling beim Menschen vorstellen: es wäre,
als müsste man als Mensch mit einer fetten Ratte, die einen in den Rücken gebissen hat und
seitdem dort festhängend Nahrung saugt, herumlaufen und trotzdem noch fröhlich seine
Arbeit machen. Will man nicht haben und daher auf zum Programmieren des „Varro Invaders“!
In der Realität geht der Imker mit diversen Mitteln gegen Varroa vor, was aber als Spiel nicht so
lustig wäre. Daher müssen wir als Kampfbiene unseren Bienenstock geben die böse
Varroamilbe (lat. Varroa destructor) verteidigen.
Im Gegensatz zu Space Invaders spielt sich unser Spielgeschehen von rechts nach links ab.
Unsere Kampfbiene bewegt sich vor dem Bienenstock und kann einen Honigtropen abfeuern.
Die Schädlinge mit dem Namen Varroa kommen je nach Level in einer bestimmten Anzahl und
wandern von hoch und runter. Jedes Mal, wenn diese am Fensterrand angekommen sind,
kommen diese dem Bienenstock näher.
Je nach Level sind es mehr Gegner und bewegen sich auch schneller.
anspruchsvoller: die Varroamilbe klebt sich an die Kampfbiene und diese wird schwerfälliger,
was sich direkt in der Steuerung auswirkt. Ab 3 angeklebten Milben war es das für unsere
tapfere Kampfbiene
unsere Gegner als Grafik (kommt im passenden Zeitpunkt bei der Umsetzung)
ein Hintergrundbild
eine Hintergrundmusik
zusätzlich natürlich ein Glas deutscher Imkerhonig (wichtig: wenn auf einem Honigglas so ein
Satz „aus EU- und Nicht-EU Ländern“ steht, dann stehen lassen. Wir wollen das reine
Honigerlebnis, ohne das verschiedene zusammengerührt werden. Zusätzlicher „Funfact“: Honig
ist das weltweit am meisten gefälschte Lebensmittel
Punktestand anzeigen
Game over
# Variablen/KONSTANTEN setzen
W, H = 800, 600
FPS = 30
SCHWARZ = ( 0, 0, 0)
WEISS = ( 255, 255, 255)
spielaktiv = True
# Schleife Hauptprogramm
while spielaktiv = False:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
# Beenden bei [ESC] oder [X]
if event.type==QUIT or (event.type==KEYDOWN and event.key==K_ESCAPE):
spielaktiv = False
# Spiellogik
# Spielfeld löschen
fenster.fill(WEISS)
# Spielfeld/figuren zeichnen
# Fenster aktualisieren
pygame.display.flip()
clock.tick(FPS)
Und was wäre bisher ein Spiel ohne eigene Spielerfigur. Diese folgt im nächsten Kapitel.
© https://www.python-lernen.de/invaders-game-python-spielerfigur.htm Seite 494
spieler = pygame.image.load("bilder/biene-sprite-sheet.png")
Für die Animation benötigen wir noch die einzelnen Bereiche der Bewegung aus dem Sprite-
Sheet:
bereich = ['','','','','','']
bereich[0] = (0,0,100,100)
bereich[1] = (101,0,100,100)
bereich[2] = (202,0,100,100)
bereich[3] = (303,0,100,100)
bereich[4] = (404,0,100,100)
bereich[5] = (505,0,100,100)
Auch sollten wir eine Variable für den aktuellen Bewegungsframe festlegen, damit wir die
Animation durchlaufen lassen können. Nennen wir die Variable hier animbereich und geben
diesem als Start die 0:
animbereich = 0
Alles das kommt vor der Hauptschleife. Hier der bisher entstandene Code komplett:
© https://www.python-lernen.de/invaders-game-python-spielerfigur.htm Seite 495
# Variablen/KONSTANTEN setzen
W, H = 800, 600
FPS = 30
SCHWARZ = ( 0, 0, 0)
WEISS = ( 255, 255, 255)
spielaktiv = True
spieler = pygame.image.load("bilder/biene-sprite-sheet.png")
bereich = ['','','','','','']
bereich[0] = (0,0,100,100)
bereich[1] = (101,0,100,100)
bereich[2] = (202,0,100,100)
bereich[3] = (303,0,100,100)
bereich[4] = (404,0,100,100)
bereich[5] = (505,0,100,100)
animbereich = 0
# Schleife Hauptprogramm
while spielaktiv = False:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
# Beenden bei [ESC] oder [X]
if event.type==QUIT or (event.type==KEYDOWN and event.key==K_ESCAPE):
spielaktiv = False
# Spiellogik
# Spielfeld löschen
fenster.fill(WEISS)
# Spielfeld/figuren zeichnen
# Fenster aktualisieren
pygame.display.flip()
clock.tick(FPS)
Jetzt müssen wir unsere Biene zeichnen und die Animation kontinuierlich durchlaufen lassen.
Dies geschieht in der Hauptschleife unseres Spiels:
© https://www.python-lernen.de/invaders-game-python-spielerfigur.htm Seite 496
# Spielfeld/figuren zeichnen
animbereich += 1
if animbereich > 5:
animbereich = 0
Wir wollen unsere Spielerfigur nach oben und unten bewegen können. Dazu legen wir eine
weitere Variable fest, in der die aktuelle Position der Spielerfigur hinterlegt ist. Auch diese
Variable kommt vor unsere Hauptschleife:
spielerposY = 300
Jetzt müssen wir die Tastatur abfragen und entsprechend auf einen Tastendruck des Spielers
reagieren. Wer in aller Ausführlichkeit über Tastaturabfragen lesen mag, kann das im Kapitel
https://www.python-lernen.de/pygame-tastatur-abfragen.htm tun.
Für uns ist wichtig, dass wir im Bereich event die entsprechende Abfrage der „Pfeil nach
oben“ bzw. „nach unten“-Taste einbauen:
# Schleife Hauptprogramm
while spielaktiv:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
# Beenden bei [ESC] oder [X]
if event.type==QUIT:
spielaktiv = False
if event.type == KEYDOWN:
# print("Spieler hat Taste gedrückt")
Somit fragen wir die Tasten ab und bekomme ein Feedback in der Konsole. Jetzt soll sich
unsere Spielerfigur auch bewegen. Wir benötigen eine weitere Variable, in der die
Bewegungsrichtung hinterlegt ist: spielerbewegung . Diese müssen wir im Vorfeld bei den
Variablen auf 0 setzen und dann je nach Taste entsprechend ändern:
spielerbewegung = 0
Und bei der Tastaturabfrage wird die Variable entsprechend gesetzt – bei einer Bewegung nach
unten mit „+6“ und nach oben mit „-6“:
© https://www.python-lernen.de/invaders-game-python-spieler-steuerung.htm Seite 498
# Spiellogik
if spielerbewegung != 0:
spielerposY += spielerbewegung
Die Berechnung über „+=“ wirkt sich korrekt auf das Ergebnis aus, denn wenn als Wert der
Spielerbewegung eine negative Zahl angeliefert wird, wird diese von der aktuellen
Spielerposition abgezogen.
Damit sich aber unsere Figur überhaupt bewegt, müssen wir bei blit() die entsprechende
Variable auch einsetzen:
# Variablen/KONSTANTEN setzen
W, H = 800, 600
FPS = 30
SCHWARZ = ( 0, 0, 0)
WEISS = ( 255, 255, 255)
spielaktiv = True
spieler = pygame.image.load("bilder/biene-sprite-sheet.png")
bereich = ['','','','','','']
bereich[0] = (0,0,100,100)
bereich[1] = (101,0,100,100)
bereich[2] = (202,0,100,100)
bereich[3] = (303,0,100,100)
bereich[4] = (404,0,100,100)
bereich[5] = (505,0,100,100)
animbereich = 0
spielerposY = 300
spielerbewegung = 0
# Schleife Hauptprogramm
while spielaktiv:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
# Beenden bei [ESC] oder [X]
if event.type==QUIT:
spielaktiv = False
if event.type == KEYDOWN:
# print("Spieler hat Taste gedrückt")
# Spiellogik
if spielerbewegung != 0:
spielerposY += spielerbewegung
# Spielfeld löschen
fenster.fill(WEISS)
# Spielfeld/figuren zeichnen
animbereich += 1
if animbereich > 5:
animbereich = 0
# Fenster aktualisieren
pygame.display.flip()
clock.tick(FPS)
Wenn wir die Bewegung stoppen wollen, wenn die Taste nicht mehr gedrückt ist, fragen wir
einfach das „loslassen“ der Taste ab und setzen dann den Wert der Variablen
spielerbewegung auf 0. Man könnte noch zusätzlich abfragen, ob die Pfeil-hoch- bzw.
Pfeil-unten-Taste losgelassen wurde.
© https://www.python-lernen.de/invaders-game-python-spieler-steuerung.htm Seite 500
if event.type == KEYDOWN:
# print("Spieler hat Taste gedrückt")
if event.type == KEYUP:
print("Spieler stoppt bewegung")
spielerbewegung = 0
Wir können uns allerdings nicht unendlich in eine Richtung bewegen, sonst sind wir als
Spielerfigur weg vom Fenster (wir haben uns dann in den unsichtbaren Bereich bewegt, was
wenig hilfreich ist). Im folgenden Kapitel begrenzen wir die Bewegungsmöglichkeit.
© https://www.python-lernen.de/invaders-game-python-bewegung-begrenzen.htm Seite 501
Gerade passiert unserer Spielerfigur auch noch, dass diese sich aus dem bestehenden
Fenster bewegen kann – sprich diese ist dann auch „weg vom Fenster“ was wenig hilfreich
für das Spielgeschehen ist.
Wir können die Spielerfigur aus dem Spielfeld nach oben bzw. nach unten bewegen, wenn wir
zu lange in eine Richtung gehen (im Fall unserer Biene „fliegen“). Suboptimal!
Also fragen wir die Position ab und alles über 0 geht nicht bzw. alles was Größer ist als die
Fensterhöhe:
# Spiellogik
if spielerbewegung != 0:
spielerposY += spielerbewegung
if spielerposY < 0:
spielerposY = 0
spielerbewegung = 0
Für die untere Stoppmarke wird die Höhe des Fensters minus der Höhe der Biene berechnet.
Daher die „- 90“.
© https://www.python-lernen.de/invaders-game-python-gegener-einbauen.htm Seite 502
# Gegner
gegnerBild = pygame.image.load("bilder/varroa.png")
gegnerX = W - 100
gegnerY = 20
gegnerbewegung = 0
Da sich unser Gegner auch in X-Richtung bewegt, benötigen auch dafür eine Variable!
# Spielfeld/figuren zeichnen
animbereich += 1
if animbereich > 5:
animbereich = 0
Soweit sollte das nun funktionieren. Wir erhalten als Ausgabe unsere Spielfigur und den
ersten Gegner.
Nachdem wir nicht nur einen Gegner haben werden, ist es hilfreich eine Funktion für die
Ausgabe der Gegner zu erstellen. Wir nehmen also die Ausgabe über blit() aus der
Hauptschleife und erstellen eine Funktion:
Vor der Hauptschleife erstellen wir eine Funktion für die Ausgabe des Gegners:
# Schleife Hauptprogramm
Und in der Hauptschleife den Aufruf der Funktion zum Zeichnen des Gegners:
© https://www.python-lernen.de/invaders-game-python-gegener-einbauen.htm Seite 503
# Spielfeld/figuren zeichnen
animbereich += 1
if animbereich > 5:
animbereich = 0
# Variablen/KONSTANTEN setzen
W, H = 800, 600
FPS = 30
SCHWARZ = ( 0, 0, 0)
WEISS = ( 255, 255, 255)
spielaktiv = True
spieler = pygame.image.load("bilder/biene-sprite-sheet.png")
bereich = ['','','','','','']
bereich[0] = (0,0,100,100)
bereich[1] = (101,0,100,100)
bereich[2] = (202,0,100,100)
bereich[3] = (303,0,100,100)
bereich[4] = (404,0,100,100)
bereich[5] = (505,0,100,100)
animbereich = 0
spielerposY = 300
spielerbewegung = 0
# Gegner
gegnerBild = pygame.image.load("bilder/varroa.png")
gegnerX = W - 100
gegnerY = 20
gegnerbewegung = 0
# Schleife Hauptprogramm
while spielaktiv:
© https://www.python-lernen.de/invaders-game-python-gegener-einbauen.htm Seite 504
while spielaktiv:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
# Beenden bei [ESC] oder [X]
if event.type==QUIT:
spielaktiv = False
if event.type == KEYDOWN:
# print("Spieler hat Taste gedrückt")
if event.type == KEYUP:
# print("Spieler stoppt bewegung")
spielerbewegung = 0
# Spiellogik
if spielerbewegung != 0:
spielerposY += spielerbewegung
if spielerposY < 0:
spielerposY = 0
spielerbewegung = 0
# Spielfeld löschen
fenster.fill(WEISS)
# Spielfeld/figuren zeichnen
animbereich += 1
if animbereich > 5:
animbereich = 0
# Fenster aktualisieren
pygame.display.flip()
clock.tick(FPS)
© https://www.python-lernen.de/invaders-game-python-gegener-einbauen.htm Seite 505
Und nun können wir eine zufällige Position über die Anweisung random.randint()
erreichen. Wir müssen uns nur überlegen, wo der Feind auftauchen soll.
zwischen Y > 50
# Gegner
gegnerBild = pygame.image.load("bilder/varroa.png")
# gegnerX = W - 100
gegnerX = random.randint(W/2, W-50)
# gegnerY = 20
gegnerY = random.randint(50, H-50)
© https://www.python-lernen.de/invaders-game-python-gegener-bewegen-lassen.htm Seite 506
Die Schnelligkeit der Gegnerbewegung setzen wir für den Level 1 dann auf gegnerbewegung
= 5
gegnerY += gegnerbewegung
Jetzt haben wir das gleiche Thema wie beim Spieler: Der Gegner verschwindet aus dem
sichtbaren Bereich des Fensters. Also auch hier die Abfragen für die Randberührung:
gegnerY += gegnerbewegung
Nun bewegt sich der Gegner von oben nach unten und andersherum, sobald der den
Fensterrand erreicht.
Zusätzlich soll er beim Erreichen des Fensterrands noch in die Richtung des Spielers sich
bewegen:
gegnerY += gegnerbewegung
Soweit so gut. Dies ist eine sehr zufällige Bewegung. Im Original bewegen sich dann alle
Gegner fein säuberlich sortiert in Reihen.
Auch die Geschwindigkeit während des Spiels des Gegners sollten wir ja nach Level
entsprechend erhöhen und die Schwierigkeit des Spiels in den höheren Leveln zu steigern.
© https://www.python-lernen.de/invaders-game-python-gegner-abschiessen.htm Seite 507
# Kugel
kugel = pygame.image.load("bilder/honigtropfen.png")
Und wir setzen gleich alle benötigten Variablen für unser Geschoss:
# Kugel
kugel = pygame.image.load("bilder/honigtropfen.png")
kugelX = 0
kugelY = 0
kugelXbewegung = 12
Und jetzt wir unsere Kugel nur in Aktion kommen, wenn der Spieler diese abfeuert. Also
brauchen wir den aktuellen Status der Kugel, der für den Anfang „False“ ist:
kugelstatus = False
Diesen Status ändern wir, sobald der Spieler die Leertaste drückt. Zusätzlich geben wir der
Kugel die X und Y-Position mit, die abhängig ist von der Spielerfigur. Wir brauchen zur Y-
Position noch eine Addition von 50, damit die Kugel ungefähr beim Kopf der Biene startet.
Und nun kommen wir zum Teil, dass die Kugel gezeichnet wird und sich bewegt. Für das
zeichnen erstellen wir eine Funktion ähnlich wir für unseren Gegner:
© https://www.python-lernen.de/invaders-game-python-gegner-abschiessen.htm Seite 508
Der Aufruf erfolgt nur, wenn der Status der Kugel auf „True“ gesetzt ist:
# Spielfeld/figuren zeichnen
animbereich += 1
if animbereich > 5:
animbereich = 0
if kugelstatus == True:
kugelfliegt(kugelX,kugelY)
Nun wird unsere Kugel angezeigt, wenn die Leertaste gedrückt wird:
Sobald also der Status der Kugel „True“ ist, darf diese auch losfliegen. Dazu erweitern wir
unseren Bereich „# Spiellogik“
if kugelstatus == True:
kugelX += kugelXbewegung
Allerdings gilt auch bei der Kugel: wenn diese trifft (soweit sind wir noch nicht) oder das
Spielfenster verlässt, dann müssen wir reagieren. Also erst einmal, wenn die Kugel das Fenster
verlässt (was wir nur überprüfen müssen, wenn die Kugel aktiv ist):
if kugelstatus == True:
kugelX += kugelXbewegung
if kugelX > W:
kugelstatus = False
Jetzt kommt noch die Besonderheit – es darf keine neue Kugel abgeschossen werden, solange
eine noch im Spiel sich befindet! Sonst wäre es ja zu einfach. Wir erweitern unsere Abfrage von
der Leertaste.
© https://www.python-lernen.de/invaders-game-python-collision-detection-geschoss-gegner.htm Seite 510
Jetzt kommt eine kleine Portion Mathe ins Spiel – endlich kann man auch mal Schulwissen
ergiebig umsetzen. Das Zauberwort bei dem Abstand zwischen zwei Punkten im kartesischen
Koordinatensystem basiert auf den Satz des Pythagoras. Damit kann man sich die folgende
Formel herleiten, um die Berechnung des Abstands zweier Punkte durchzuführen. Lange her?
Egal – wenn man die Formel sieht, darf man nicht erschrecken:
Also wenden wir diese Formel für die Berechnung des Abstands zweier Punkte einfach an.
Grundsätzlich benötigen wir nun auch das Python-Modul „math“, das wir am Anfang unseres
Python-Programms importieren:
Dazu Erstellen wir eine neue Funktion in Python mit dem Namen „kollisionskontrolle()“.
In dieser Funktion benötigen wir für die Berechnung die Position unserer Kugel (X wie Y) wie
auch die Position unseres Gegners (X wie Y):
Wir lassen uns in der Konsole nun auch die Werte für den Abstand zwischen Kugel und Gegner
ausgeben. Hier sieht man schön den Abstand (mit zig Nachkommastellen). Das ist deutlich zu
viel der Genauigkeit. Also lassen wir uns einfach Ganzzahlen über int() zurückliefern.
Und jetzt können wir einfach festlegen, wenn die Kugel trifft. Wir lassen uns von der Funktion
„True“ zurückliefern, wenn die Distanz unter 25 liegt und „False“, wenn die Kugel weiter vorbei
geht.
© https://www.python-lernen.de/invaders-game-python-collision-detection-geschoss-gegner.htm Seite 511
Wenn man genau hinsieht, merkt man, dass die Kugel auch oberhalb trifft aber nicht die
komplette Gegnerfigur am unteren Bereich. Diese Ungenauigkeit kommt daher, dass wir für die
Berechnung die Punkt 0,0 von den Grafiken nehmen. Aber unsere Kugel ist 19 hoch und der
Gegner hat eine Höhe von 50. Wenn wir also eine Y-Korrektur von 25 vornehmen, dass sollte
das Treffen deutlich besser passen – zusätzlich noch eine Korrektur bei X um 30 (was der
Kugelbreite entspricht):
Und können nun können wir auf einen Treffer entsprechend reagieren:
if kugelstatus == True:
kugelX += kugelXbewegung
if kugelX > W:
kugelstatus = False
Natürlich wollen wir auch Siegpunkte für einen Treffer. Also führen wir eine Variable für die
Siegpunkte mit dem aussagekräftigen Namen „siegpunkte“ ein und bei jedem Treffer wird
diese um 1 erhöht und in der Konsole ausgeben.
Testen
# Variablen/KONSTANTEN setzen
W, H = 800, 600
© https://www.python-lernen.de/invaders-game-python-collision-detection-geschoss-gegner.htm Seite 512
FPS = 30
SCHWARZ = ( 0, 0, 0)
WEISS = ( 255, 255, 255)
spielaktiv = True
spieler = pygame.image.load("bilder/biene-sprite-sheet.png")
bereich = ['','','','','','']
bereich[0] = (0,0,100,100)
bereich[1] = (101,0,100,100)
bereich[2] = (202,0,100,100)
bereich[3] = (303,0,100,100)
bereich[4] = (404,0,100,100)
bereich[5] = (505,0,100,100)
animbereich = 0
spielerposY = 300
spielerbewegung = 0
# Gegner
gegnerBild = pygame.image.load("bilder/varroa.png")
# gegnerX = W - 100
gegnerX = random.randint(W/2, W-50)
# gegnerY = 20
gegnerY = random.randint(50, H-50)
gegnerbewegung = 5
# Kugel
kugelBild = pygame.image.load("bilder/honigtropfen.png")
kugelX = 0
kugelY = 0
kugelXbewegung = 12
kugelstatus = False
siegpunkte = 0
return True
else:
return False
# Schleife Hauptprogramm
while spielaktiv:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
# Beenden bei [ESC] oder [X]
if event.type==QUIT:
spielaktiv = False
if event.type == KEYDOWN:
# print("Spieler hat Taste gedrückt")
if event.type == KEYUP:
# print("Spieler stoppt bewegung")
spielerbewegung = 0
# Spiellogik
if spielerbewegung != 0:
spielerposY += spielerbewegung
if spielerposY < 0:
spielerposY = 0
spielerbewegung = 0
gegnerY += gegnerbewegung
gegnerX -= 30
if kugelstatus == True:
kugelX += kugelXbewegung
if kugelX > W:
kugelstatus = False
# Spielfeld löschen
fenster.fill(WEISS)
# Spielfeld/figuren zeichnen
animbereich += 1
if animbereich > 5:
animbereich = 0
if kugelstatus == True:
kugelfliegt(kugelX,kugelY)
gegner(gegnerX, gegnerY)
# Fenster aktualisieren
pygame.display.flip()
clock.tick(FPS)
Wenn wir jetzt den einzigen Gegner killen, wäre das Spiel sofort aus. Also brauchen wir
dringend mehr Gegner. Im nächsten Kapitel erzeugen wir jede Menge Gegner getreu dem
Motto: „viel Gegner, viel Ehr“.
© https://www.python-lernen.de/invaders-game-python-viele-gegner.htm Seite 515
# Gegner
# gegnerBild = pygame.image.load("bilder/varroa.png")
# gegnerX = random.randint(W/2, W-50)
# gegnerY = random.randint(50, H-50)
# gegnerbewegung = 5
gegnerBild = []
gegnerX = []
gegnerY = []
gegnerbewegung = []
anzahlgegner = 5
Über eine for -Schleife lassen wir nun unsere Gegner als Liste erstellen:
for x in range(anzahlgegner):
gegnerBild.append(pygame.image.load("bilder/varroa.png"))
gegnerX.append(random.randint(W/2, W-50))
gegnerY.append(random.randint(50, H-50))
gegnerbewegung.append(5)
Ab jetzt müssen wir bei jeder Aktion, die wir für einen Gegner machen (egal ob bewegen oder
Kontrolle auf Treffer), für alle unsere Gegner durchführen.
Gehen wir unser bestehendes Programm durch und ändern die entsprechenden Stellen:
gegnerY += gegnerbewegung
Wird nun folgender Code für unsere Gegner, die aus der Liste kommen. Da nach einem Treffer
die Anzahl der Gegner sich ändert, lassen wir uns die Anzahl der Einträge die Liste über
len() jeweils berechnen:
© https://www.python-lernen.de/invaders-game-python-viele-gegner.htm Seite 516
for x in range(len(gegnerBild)):
gegnerY[x] += gegnerbewegung[x]
if kugelstatus == True:
kugelX += kugelXbewegung
for x in gegnerBild:
if kollisionskontrolle(kugelX,kugelY,gegnerX[x], gegnerY[x]) == True:
for x in range(len(gegnerBild)):
gegner(gegnerX[x], gegnerY[x])
Wobei wir die Funktion erweitern über die Nummer des Gegners:
for x in range(len(gegnerBild)):
gegner(x, gegnerX[x], gegnerY[x])
Und wenn sich kein Tippfehler eingeschlichen hat, wuselt es auf dem Bildschirm:
Jetzt soll auch bei einem Treffer der entsprechende Gegner verschwinden. Getroffen ist
schließlich getroffen!
for x in gegnerBild:
if kollisionskontrolle(kugelX,kugelY,gegnerX[x], gegnerY[x]) == True:
# Kugel hat getroffen
# print("Kugel hat getroffen")
siegpunkte += 1
print("aktueller Stand der Siegpunkte: ", siegpunkte)
kugelstatus = False
Allerdings stürzt nun unser Programm bei einem Treffer ab. Was passiert da. Wir löschen ein
Element aus unserer Liste und versuchen die alte Anzahl von Listenelementen durchzugehen.
Unsere Variable mit x enthält nicht das, was wir glauben, dass diese enthält. Eine Liste wird
nach dem löschen automatisch mit einem neuen Index versehen.
Und hier kommt dann gezieltes debuggen zum Einsatz. Wir wollen unser Programm vor dem
Crash anhalten.
Wir wissen, dass es ein Problem nach dem Treffer und löschen im Index gibt. Also geben wir
da unserem Programm ein exit() mit und starten das Programm mit dem Paramater -i
python3 -i varroa-invaders.py
Jetzt kommt man sehr schnell darauf, dass wir unsere x so nicht verwenden können. Wir
basteln uns eine Hilfvariable mit dem Namen durchgang , die wir bei 0 starten und bei jedem
Durchgang erhöhen.
Findet ein Treffer statt, dann können wir den Listeneintrag mit der Nummer von „durchgang“
löschen.
durchgang = 0
for x in gegnerBild:
if kollisionskontrolle(kugelX-30,kugelY-25,gegnerX[durchgang], gegnerY[durchga
# Kugel hat getroffen
# print("Kugel hat getroffen")
siegpunkte += 1
print("aktueller Stand der Siegpunkte: ", siegpunkte)
kugelstatus = False
del gegnerNr[durchgang]
del gegnerBild[durchgang]
del gegnerX[durchgang]
del gegnerY[durchgang]
del gegnerbewegung[durchgang]
durchgang += 1
© https://www.python-lernen.de/invaders-game-python-viele-gegner.htm Seite 518
© https://www.python-lernen.de/invaders-game-python-spiel-gewonnen.htm Seite 519
# Spielfeld löschen
# für Textausgabe
font = pygame.font.Font(None, 36)
Und nun können wir die Punkte ausgeben, nachdem wir den Bildschirm gelöscht haben:
# Spielfeld löschen
fenster.fill(WEISS)
# Siegpunkte ausgeben
inhalt = "Punkte: {}".format(siegpunkte)
text = font.render(inhalt, 1, SCHWARZ)
fenster.blit(text, (20,20))
© https://www.python-lernen.de/invaders-game-python-sound-integrieren.htm Seite 521
# für Textausgabe
font = pygame.font.Font(None, 36)
# Musik/Soundeffekte einrichten
pygame.mixer.music.load('sound/bienensummen.mp3')
pygame.mixer.music.play(-1,0.0)
pygame.mixer.music.set_volume(.4)
getroffen = pygame.mixer.Sound('sound/treffer.wav')
Gegner getroffen
if kollisionskontrolle(kugelX-30,kugelY-25,gegnerX[durchgang], gegnerY[durchga
# Kugel hat getroffen
# print("Kugel hat getroffen")
pygame.mixer.Sound.play(getroffen)
© https://www.python-lernen.de/raspberry-pi-python-interpreter.htm Seite 522
Die Benennung des Einplatinencomputer steht in der Tradition, Computern mit Früchtenamen
zu versehen wie z.B. „apple“. Wobei die Aussprache auf den englischen Kuchen („Pie“) abzielt –
es handelt sich also um einen Himbeerkuchen. Ursprünglich wurde geplant, Python fest
eingebaut werden. Daher auch das Kürzel „Pi“, was für „Python Interpreter“ steht.
© https://www.python-lernen.de/impressum.php Seite 523
Kontakt/Impressum
Impressum gemäß §6 Teledienstegesetz (TDG)
Verantwortlicher Redakteur und Webmaster für die Planung, Realisierung und Betreuung der
Internetinhalte sowie für die Administration der Domains www.python-lernen.de und
www.pythonlernen.de (Admin-c) ist:
Axel Pratzner
Albblickweg 9
73560 Böbingen
E-Mail kontakt python-lernen.de
Internet: https://www.python-lernen.de/
Tel. 0 71 73-9 14 66 2 + eine weitere Nummer - aber erst weiterlesen! Bitte keine Anrufe! Ich bin
gesetzlich verpflichtet, hier eine Nummer anzugeben. Ich biete keine telefonische Beratung,
daher bitte bei Kontaktaufnahme die E-Mail-Adresse nutzen - und die 9 ist die letzte Nummer
zur kompletten Telefonnummer. Danke für die Berücksichtigung.
https://www.python-lernen.de
Das Projekt verfolgt keine kommerziellen Interessen, sondern dient als Kursunterlagen zu
meinen Kursen. Falls Sie Fragen, Kritik oder Anregungen zu diesem Internetprojekt haben, dann
senden Sie einfach eine E-Mail.
Bildquellen
Verwendete Bilder (sofern nicht anders gekennzeichnet) stammen aus dem eigenen Fundus.
Eine Nutzung meiner Bilder zu kommerziellen Zwecken und Veröffentlichung auf anderen
Internetseiten und Medien ist untersagt, sofern ich nicht zugestimmt habe. Eine Nutzung in
Schulbüchern und im Schulunterricht ist ausdrücklich erlaubt bei Namensnennung und der
Nennung der URL der Website - bei Veröffentlichungen mir bitte Bescheid geben.