Hier ist eine Reihe von Themenbereichen aufgelistet, die du einzeln auf- und zuklappen kannst (Klick auf die kleine Pfeilspitze).
Die wichtigsten Informationen sind schwarz geschrieben.
Zusatz- oder Hintergrundinformationen sind grau geschrieben.
Wenn ich eine Funktion definiere, programmiere ich aus Einzelteilen einen Baustein, den ich später (mithilfe des von mir festgelegten Funktionsbezeichners) als Ganzen verwenden kann.
Eine Funktion kann dazu dienen, einfach nur für gegebene Übergabewerte genau einen Rückgabewert bzw. Funktionswert zu berechnen (entsprechend einer Funktion in der Mathematik). Sie kann aber (vorher) auch noch allerhand anderes erledigen. Und sie kann auch nur anderes erledigen, ohne einen Rückgabewert zu berechnen.
Allgemein: | Beispiele: |
---|---|
|
|
Die Parameter aus der Parameterliste sind nur "innerhalb der jeweiligen Funktion", hier also im eingerückten Code nach dem Doppelpunkt, gültig.
Beachte, dass bei Funktionen, die Methoden einer Klasse sind, an erster Stelle in der Parameter-Liste self
stehten muss.
Nachdem eine Funktion definiert worden ist, kann ich sie in einem Term (allein oder in Kombination) verwenden. Wir sprechen auch davon, dass ich eine Funktion "aufrufe". Dabei benutze ich den Bezeichner der Funktion, gefolgt von der Parameterliste, in der jetzt für jeden Parameter ein passender Übergabewert stehen muss.
Funktionsdefinition: | Verwendung/Aufruf der Funktion: |
---|---|
|
|
Wenn die Funktion einen Rückgabewert erzeugt, hat der Funktionsaufruf im Term den Wert des Rückgabewerts.
Term | Wert des Terms |
---|---|
|
|
|
|
Eine Variable ermöglicht es, Werte im Arbeitsspeicher zu speichern, um sie zu einem späteren Zeitpunkt wieder abzurufen und damit weiterzuarbeiten. Mit einer Variablen kann ich das über einen von mir selbst festgelegten Bezeichner tun.
So muss ich mich nicht darum kümmern, wie ein geeigneter Speicherplatz gefunden werden kann, über welche Speicheradresse (eine Zahl) darauf zugegriffen werden muss, wie sichergestellt wird, dass kein anderes Programm mir meine Werte überschreibt usw.
Allgemein: | Beispiel: |
---|---|
bezeichner |
|
Wenn ich einen Variablenbezeichner in einem Term benutze, wird er durch den aktuellen Wert der Variable ersetzt.
Schreibe ich aber nach einem Variablenbezeichner ein =
-Zeichen, so muss darauf ein Term folgen. Der Wert dieses Terms wird der Variable dann als neuer Wert zugewiesen. Dabei muss ich selbst darauf achten, dass der Datentyp des neuen Wertes zur Verwendung der Variablen passt.
Deklaration & Initialisierung: | Verwendung der Variable: |
---|---|
|
|
|
|
Wenn es gerade keinen sinnvollen Wert für eine Variable gibt, kann ihr das Platzhalter-Objekt None
als Wert zugewiesen werden.
Ein Algorithmus ist eine endliche Folge eindeutiger Anweisungen, die, wenn sie unter gleichen Ausgangsbedingungen ausgeführt wird, zum gleichen Ergebnis führt. Wenn ein Algorithmus in einer Programmiersprache formuliert wird, entsteht ein Programm. Die jeweilige Programmiersprache legt fest, was als eindeutige Anweisung gilt. In Python sind das Definitionen von bzw. Wertzuweisungen an Variablen, Funktionsaufrufe, Methodenaufrufe ...
Mehrere Anweisungen werden als zusammengehörig gekennzeichnet, indem sie gleich weit (um dieselbe Zahl von Leerzeichen – i. d. R. ein ganzzahliges Vielfaches von 4) eingerückt werden. Gebraucht wird das bei Funktionsdefinitionen, bedingten Anweisungen, bedingten Wiederholungen ...
Bedingte Anweisungen, bedingte Wiederholungen etc. können selbst auch innerhalb einer Sequenz vorkommen, dann gibt wird entsprechend weiter eingerückt.
Unter der gegebenen Bedingung etwas Bestimmtes machen, ansonsten gar nichts machen:
Allgemein: | Beispiel: |
---|---|
|
|
Unter der gegebenen Bedingung etwas Bestimmtes machen, ansonsten etwas anderes machen:
Allgemein: | Beispiel: |
---|---|
|
|
Wenn mehr als zwei Fälle unterschieden werden sollen, kann statt mit else:
mit elif
aussagefunktion:
weitergemacht werden; am Schluss folgt dann else:
.
Wenn die angegebene Bedingung erfüllt ist, etwas Bestimmtes machen, danach wieder von vorn prüfen, ob die Bedingung erfüllt ist, und wenn ja, dasselbe wieder machen und immer so weiter, bis die Bedingung nicht mehr erfüllt ist.
Wenn die Bedingung bei der ersten Prüfung nicht erfüllt ist, wird gar nichts gemacht (wie bei if
).
Allgemein: | Beispiel: |
---|---|
|
|
Objekte sind Bündel von Variablen und Funktionen, die unter einem einzigen Bezeichner abgespeichert werden können. Die Variablen im Bündel nennen wir Attribute, die Funktionen im Bündel nennen wir Methoden.
Solange es noch einen Bezeichner gibt, unter dem ein Objekt gespeichert ist, bleibt es – mit allen seinen Attributen und Methoden – erhalten. Gibt es keinen solchen Bezeichner mehr, wird das Objekt entsorgt.
Um Objekte zu erzeugen, programmiere ich üblicherweise eine Klasse, in der festgelegt ist, wie Objekte eines bestimmten Typs aussehen sollen. Die Klasse kann dann beliebig viele Objekte ihres Typs erzeugen. "Ihres Typs" ist hier in jeder Hinsicht wörtlich zunehmen: Mit jeder Klasse erzeuge ich auch einen neuen Datentyp. Dieser Datentyp hat denselben Bezeichner wie die Klasse.
Datenklassen legen nur Attribute, jedoch keine Methoden fest.
Allgemein: | Beispiel: |
---|---|
|
|
Eine Klasse wird einmal programmiert und dient dann als Vorlage für beliebig viele Objekte. Damit der einmal erzeugte Programmcode für jedes später erzeugte Objekt gelten kann, muss darin ein Platzhalter für das Objekt vorgesehen werden, für das er im jeweiligen Fall genutzt werden soll. Dazu dient der erste Parameter jeder Methode, der normalerweise self
genannt wird (obwohl er auch anders heißen könnte). Wenn später eine Methode eines Objekts aufgerufen wird, liefert das System automatisch eine Referenz auf das entsprechende Objekt mit. So wird im Beispiel oben sichergestellt, dass die umfang_geben
-Methode eines Objekts von der Klasse Quadrat
für die Berechnung des Umfangs wirklich die Kantenlänge desjenigen Quadrat
-Objekts benutzt, zu dem sie gehört.
Die Attribute der Klasse werden, mit vorangestelltem self.
, in der __init__
-Methode deklariert. Sie können mit Übergabewerten aus Parametern der Methode initialisiert werden oder auch mit festen Werten.
Um ein Objekt zu erzeugen, benutze ich den Klassenbezeichner wie einen Funktionsbezeichner (es soll ja eine Funktion ausgeführt werden, die ein Objekt erzeugt). In die Parameterliste muss ich die nötigen Übergabewerte für die __init__
-Methode(!) eintragen (ohne den Übergabewert für self
, der wird, wie gesagt, automatisch bereitgestellt).
Klassendefinition: | Erzeugung und Verwendung von Objekten: |
|
|
---|
Typischerweise werden neu erzeugte Objekte (wie hier im Beispiel) direkt einer Variablen als Wert zugewiesen. Das muss aber nicht sein: Was im Beispiel hinter dem =
-Zeichen steht, könnte z. B. auch in einem Funktionsaufruf als Übergabewert verwendet werden.
Mithilfe der Punktnotation kann ich auf die Attribute und Methoden von Objekten zugreifen. Ich schreibe vor dem Punkt einen Objektbezeichner (also den Bezeichner einer Variable, als deren Wert ein Objekt gespeichert ist) und nach dem Punkt einen Attribut- bzw. Methodenbezeichner (jeweils ohne Leerzeichen dazwischen). Zusammen lässt sich dies genau so verwenden wie ein einfacher Variablen- bzw. Funktionsbezeichner (denke aber bei Methodenaufrufen daran, dass der Übergabewert für self
automatisch bereitgestellt wird).
Jedem Objekt soll die Kontrolle darüber, was mit seinen – in den Attributen gespeicherten – Daten gemacht wird, selbst überlassen werden. Andere Programmteile sollen lieber nicht (insbesondere nicht schreibend) auf die Attribute eines Objekts zugreifen. Das ist aber, wie oben festgestellt, in Python grundsätzlich möglich: Mithilfe der Punktnotation kann ich Attributwerte nicht nur lesen, sondern – per Zuweisungsoperator =
– auch schreiben.
Was tun?
Eine Unterklasse "erbt" alle Attribute und Methoden ihrer Oberklasse. Üblicherweise "erweitert" sie die Oberklasse durch weitere Attribute bzw. Methoden. Oder sie "überschreibt" bestimmte Methoden, die sie geerbt hat.
Wenn ich in einer Klassendefinition hinter dem Klassenbezeichner in Klammern den Bezeichner einer anderen Klasse angebe, wird die neu definierte Klasse eine Unterklasse der in Klammern angegebenen Oberklasse.
Definition einer Unterklasse allgemein: |
---|
|
In der __init__
-Methode der Unterklasse muss (am besten gleich am Anfang) die __init__
-Methode der Oberklasse (Zugriff über die super
-Funktion) aufgerufen werden, damit die in der Oberklasse vorgesehenen Attribute richtig angelegt werden. Ob die Übergabewerte dafür aus der Parameterliste der __init__
-Methode der Unterklasse stammen oder ob sie anders ermittelt werden, hängt von den jeweiligen Erfordernissen ab.
Beispiel für eine Oberklasse: |
---|
|
Beispiel für eine Unterklasse dazu: |
---|
|
Im Beispiel gibt die Unterklasse für die zwei Attribute der Oberklasse denselben Startwert an die Oberklasse weiter (weil das in diesem Zusammenhang sinnvoll ist). Die umfang_geben
-Methode der Oberklasse wird von der Unterklasse (mit einer anderen, die etwas weniger aufwändig rechnet) überschrieben. Die flaeche_geben
-Methode wird in der Unterklasse so beibehalten, wie sie von der Oberklasse geerbt wurde.
Hinweis zum Überschreiben: Wenn eine Methode einer Unterklasse eine Methode einer Oberklasse überschreibt, kann bei Bedarf unter Rückgriff auf die super
-Funktion aus der Unterklassen-Methode heraus die entsprechende Oberklassen-Methode aufgerufen werden.
Zum Erzeugen von Objekten einer Unterklasse gibt es nichts Besonderes anzumerken.
Listen erlauben es, beliebig viele (normalerweise gleichartige) Werte bzw. Objekte gemeinsam unter einem Bezeichner zu speichern. Die Werte werden in der Liste an aufsteigend durchnummerierten Speicherplätzen abgelegt. Mit der Kombination aus dem Bezeichner einer Liste und einer Speicherplatznummer – dem sogenannten Index – kann auf die einzelnen Werte zugegriffen werden. Dabei kann der Index auch mithilfe einer Variable (vom Typ int
) angegeben werden. So ist es möglich, je nach Zustand des Sytems flexibel steuern zu lassen, auf welchen Wert zugegriffen werden soll.
Eine leere Liste erzeuge ich, indem ich eckige Klammern öffne und schließe: []
. Ich kann auch gleich Elemente mit angeben, die von vornherein in der Liste enthalten sein sollen, indem ich die entsprechenden Werte durch Komma getrennt in die eckigen Klammern schreibe.
Allgemein: | Beispiele: |
---|---|
bzw.
|
|
Manchmal möchte man eine Liste einer bestimmten Länge erzeugen, in der zunächst nur Platzhalter für die späteren Werte gespeichert sind. Dazu erzeugt man eine Liste der Länge 1, die nur den Platzhalter enthält, und 'multipliziert sie mit' einer der gewünschten Länge entsprechenden Ganzzahl, z. B. [None] * 10
.
Um an eine bereits vorhandene Liste ein Element anzuhängen kann ich deren append
-Methode benutzen. Es ist aber auch möglich, Listen zu 'addieren'.
Erzeugung und Zuweisung an eine Variable: | Verwendung der Liste: |
---|---|
|
|
Um auf einen bestimmten Wert zuzugreifen, der in einer Liste gespeichert ist, schreibe ich
bezeichner[
index]
.
Erzeugung und Zuweisung an eine Variable: | Verwendung der Liste: |
---|---|
|
|
Typischerweise werden neu erzeugte Listen (wie hier im Beispiel) direkt einer Variable als Wert zugewiesen. Das muss aber nicht sein: Was im Beispiel hinter dem =
-Zeichen steht, könnte z. B. auch in einem Funktionsaufruf als Übergabewert verwendet werden.
Um flexibel auf verschiedene Werte in einer Liste zugreifen zu können, gebe ich den Index mithilfe einer Variable an. Den Wert der Variable verändere ich im Rahmen einer bedingten Wiederholung so, dass jeder gewünschte Index einmal 'an die Reihe kommt'.
Erzeugung und Zuweisung: | Iterieren über die Liste: |
---|---|
|
Alternative: |
match
(Mustervergleich)Den Wert einer Variable mit verschiedenen Mustern vergleichen und jeweils entsprechend reagieren.
Allgemein: | Beispiel: |
---|---|
|
|
Die Muster können auch komplexer sein: Mehrere mögliche Werte können getrennt durch |
angegeben werden. ... In "Konstuktor-Mustern" steht ein Klassenbezeichner, gefolgt von einer Liste möglicher Übergabewerte für seine init-
-Methode, für ein Objekt mit entsprechenden Attributwerten ... Übergabewerte können dann durch Bezeichner zu erzeugender Variablen ersetzt werden, die jeweils mit dem entsprechenden Attributwert initialisiert werden ...
for
Einer (ggf. extra zu diesem Zweck erzeugten) Variable der Reihe nach jeden Wert aus einem Bereich von ganzzahligen Werten zuweisen – und demnach so oft wiederholen, wie es die Anzahl von Werten im Bereich vorgibt.
Allgemein: | Beispiel: |
---|---|
|
|
Die (ggf.) neu erzeugte Variable mit dem in jedem Wiederholungsdurchlauf anderen Wert kann, wie im Beispiel, in den zu wiederholenden Anweisungen verwendet werden, das muss aber nicht sein – dann liegt eine "klassische" Wiederholung mit fester Anzahl vor.
Einer Variable der Reihe nach jeden Wert aus einem Container, z. B. einer Liste, zuweisen.
Allgemein: | Beispiel: |
---|---|
|
|
Hier wird die (ggf.) neu erzeugte Variable auf jeden Fall in den zu wiederholenden Anweisungen verwendet werden.
Achtung: Wenn ich for
so verwende, kann ich mithilfe der (ggf.) neu erzeugten Variable keine Werte in den Container schreiben.
Wenn ich als Wert einer Variable ein Objekt (bzw. eine Referenz darauf) gespeichert habe, kann ich den Variablenbezeichner in der Punktnotation verwenden, um Methoden des Objekts aufzurufen. In einer Reihe von Sprachen wird sichergestellt, dass das Objekt die von mir aufgerufene Methode (wahrscheinlich) wirklich hat, indem man von vornherein festlegt, welchen Datentyp ein "in" der Variable gespeichertes Objekt haben muss – denn ein Objekt vom Typ XY
hat auch die Methoden der Klasse XY
. In Python ist ein anderer Ansatz gängig: Wenn ein Objekt die Methode, die ich aufrufen will, hat, wird das schon passen – egal welchen Datentyp das Objekt hat. Es gilt: "If it walks like a duck and swims like a duck and quacks like a duck, it must be a duck."
Das hilft mir allerdings nur dann etwas, wenn ich Objekte fragen kann, ob sie eine bestimmte Methode haben. Dazu benutze ich die vordefinierte hasattr
-Funktion.
Allgemein: | Beispiel: |
---|---|
|
|
Wenn mir das so zu unsicher ist, kann ich mithilfe der vordefinierten isinstance
-Funktion prüfen, ob ein Objekt den erwarteten Datentyp hat; hier ist der Übergabewert für den ersten Parameter ein Objektbezeichner, der für den zweiten Parameter ein Datentyp (oder ein Tupel von Datentypen oder ...).
None
-ObjektsWenn ich das None
-Objekt als Platzhalterwert verwende, weil ich gerade keinen passenden Wert zur Verfügung habe, stellt sich das oben genannte Problem in besonderer Weise: Denn zunächst einmal wird ein anderer Wert als None
erwartet – von dem sich Methoden aufrufen lassen müssten, die None
nicht hat. Wenn ich also einer Variable manchmal den Wert None
zuweise, sollte ich deren Wert, bevor ich den Bezeichner in Punktnotation verwende, mithilfe einer der oben genannten Funktionen prüfen – oder ich prüfe in einer bedingten Anweisung, ob ich es mit etwas anderem als dem None
-Objekt zu tun habe.
Beispiel: |
---|
bzw.
|
Operator: | Bedeutung: |
---|---|
| plus |
| minus |
| mal |
| geteilt durch |
| geteilt durch, ganzzahlig ohne Rest |
| modulo: Rest der ganzzahligen Division |
| hoch |
Operator: | Bedeutung: |
---|---|
| weist den Wert des Terms rechts vom Operator der Variable mit dem Bezeichner links vom Operator zu! (Wertzuweisung) |
| weist der Variable (links) ihren aktuellen Wert addiert mit dem Wert des Terms (rechts) zu |
| weist der Variable (links) die Differenz zwischen ihrem aktuellen Wert und dem Wert des Terms (rechts) zu |
| weist der Variable (links) ihren aktuellen Wert multipliziert mit dem Wert des Terms (rechts) zu |
... | usw. |
Aussagefunktionen sind Funktionen, deren Rückgabewert entweder True
oder False
ist.
Operator: | Bedeutung: |
---|---|
| ist gleich |
| ist nicht gleich |
| ist größer als |
| ist kleiner als |
| ist größer als oder gleich |
| ist kleiner als oder gleich |
| ist dasselbe Objekt wie |
| ist nicht dasselbe Objekt wie |
| ist enthalten in |
| ist nicht enthalten in |
Operator: | Bedeutung: |
---|---|
| UND |
| ODER |
| NICHT |
Bezeichner: | 'Art' der Daten: | Beispiele für Notation der Daten: |
---|---|---|
| Ganzzahl |
|
| Kommazahl |
|
| Zeichenkette |
|
Mit jeder Klasse erzeuge ich auch einen neuen Datentyp. Der Datentyp hat denselben Bezeichner wie die Klasse.