.. include:: markup.rst ******************* Standard Datentypen ******************* In den vorigen Kapiteln wurden einführende Themen behandelt und erste Eindrücke von Python gewonnen. In den folgenden Kapiteln wird die Programmiersprache :mark:`Python systematisch aufgearbeitet`. Obwohl hier auf Python fokusiert wird, sind die vorgestellten Techniken :mark:`in anderen Programmiersprachen ähnlich`. Datentypen im Überblick ======================= Eine Variable muss wissen welchen :mark:`Datentyp` sie speichern soll um entsprechend Speicher zu allozieren (Char, Integer, Gleitkomma, ...). Die folgende Abbildung zeigt `Datentypen in Python`_ im Überblick. Daraus werden in den folgenden Kapiteln die wichtigsten im Detail behandelt. .. _`Datentypen in Python`: .. figure:: images/datentypen.png :scale: 60 % :align: center Datentypen in Python Generell unterscheidet man zwischen: * Zahlen * Kollektionen * Bool'schen Variablen * None Type Wertzuweisung ============= :mark:`Datentypen` sind im Wesentlichen :mark:`Objekte` (Instanzen) welche bestimmte :mark:`Daten aufnehmen` können. Die Anweisung: :: a = 342 bewirkt eine Wertzuweisung (siehe Abbildung `Schaubild einer Wertzuweisung`_). .. _`Schaubild einer Wertzuweisung`: .. figure:: images/referenz.png :scale: 90 % :align: center Schaubild einer Wertzuweisung Genauer gesagt: * einem Objekt (Instanz) vom Typ ``int`` (Integer) wird * ein Speicherplatz mit der Identität ``28609680`` (Speicherplatznummer, Adresse) * und der Wert ``342`` zugewiesen. * Dieses Integer Objekt ("Box") bekommt den Variablennamen ``a`` welcher aus :mark:`Literalen` besteht. Vereinfacht nennt man das Ganze: :mark:`die Variable a`. **Literale**: * Das sind :mark:`Zeichenfolgen`, die nach bestimmten (zulässigen) Regeln aufgebaut sind. * :mark:`Werte` werden durch Literale dargestellt. Beispiele * Wahrheitswerte: ``True``, ``False`` * Ganzzahlen: ``13``, ``-34`` * Gleitkommazahlen: ``12.45``, ``-12.3E08`` * Zeichenketten: ``"Ein Text so"``, ``'oder so'`` Anweisung id() und type() ~~~~~~~~~~~~~~~~~~~~~~~~~ Der Datentyp und die Identität einer Variablen kann mittels ``type()`` und ``id()`` abgefragt werden: :: In [1]: a = 342 In [2]: a Out[2]: 342 In [3]: type(a) Out[3]: int In [4]: id(a) Out[4]: 2189018132976 Die :mark:`Identität` (Speicherplatzadresse) :mark:`ändert sich` bei jedem Aufruf des Skripts da ein anderer Speicherplatz belegt wird. Laufzeitmodell ~~~~~~~~~~~~~~ Darunter versteht man wie Python Variablen zur Laufzeit verwaltet. **Statische Typisierung** Bei Programmiersprachen wie Java, C++ muss eine Typisierung :mark:`von Hand` vorgenommen werden (:mark:`=statisch`) d.h.: :: int x = 15; Eine Laufzeitänderung des Typs kann nur mit einem :mark:`cast` erfolgen. Z.B. :: float *b = static_cast(a); **Dynamische Typisierung** In Python ist keine explizite Typisierung notwendig. Diese wird :mark:`automatisch zur Laufzeit` vorgenommen. Man spricht von :mark:`dynamischer Typisierung`. Beispiel :: a = 5 # Variable a ist eine Ganzzahl (int) Objekt a = "ok" # Python "loescht" das int Objekt und # Variable a ist nun ein string Objekt .. warning:: Dynamische Typisierung ist elegant aber gefährlich da sich der Datentyp während der Laufzeit ändern kann! Hier ein Beispiel: :: In [1]: x = 15 # Typ int In [2]: x = 'Hansi' # Typ von int -> string In [3]: x / 2 Traceback (most recent call last): File "", line 1, in x / 2 TypeError: unsupported operand type(s) for /: 'str' and 'int' **Variable: Kopie und Zeiger** Es gibt :mark:`2 Variablentypen:` Kopien (klassische Variable) oder Zeiger (Referenz oder Pointer). Kopien werden vereinfacht als :mark:`"Variable"` bezeichnet. Zeiger gerne als :mark:`Zeigervariable`. Variablen bzw. Zeiger auf Variablen gibt es in :mark:`allen Programmiersprachen`. In C++ wird dies in der Deklaration explizit angegeben: :: int x = 15; // Variable (Kopie) int *x; // Zeigervariable durch * gekennzeichnet Die Abbildung `Variable und Zeiger` erklärt den Unterschied grafisch: .. _`Variable und Zeiger`: .. figure:: images/Zeiger.png :scale: 90 % :align: center Erklärungen: * Die :mark:`Variablen` va, vb (Kopien) befinden sich tatsächlich :mark:`im Speicher` und belegen entsprechend Platz. * :mark:`Zeigervariable` za, zb hingegen, speichern nur die :mark:`Adresse` (Id), wo sich eine Variable befindet. * Zeiger "zeigen" auf die Variable und :mark:`belegen` bei der Erzeugung :mark:`keinen Speicherplatz` für den Wert! Dieser muss i.A. separat alloziert werden. Python Variablen können sich : * wie Variablen (Kopien) aber auch wie Zeigervariablen verhalten. * :mark:`Welche Art` Python verwendet, hängt mit den `Datentypen in Python`_ zusammen. Generell unterscheidet man 2 Python Datentypen: * :mark:`unveränderbare` im Sinne des belegten Speicherplatzes z.B. Zahlen (``int``, ``float``, ``complex``) sowie ``tuple``, ``string`` * :mark:`veränderbare` im Sinne des belegten Speicherplatzes z.B. ``list``, ``dict``, ``set`` Diese :mark:`Unterscheidung ist essentiell` für das Verstehen der Referenzierung in Python (Variablen oder Zeigerverhalten) Generell gibt es 2 Regeln: * unveränderbar: Es wird ein neuer Speicherplatz belegt, sobald eine neue Wertzuweisung erfolgt. D.h. zuerst Zeigervariable, danach klassische Variable (Kopie). Erklärung am Beispiel: :: In [1]: a = 342 # belege Speicher mit Zahl und erzeuge Zeiger a In [2]: b = a # zeige mit b auf a, b ist ein weiterer Zeiger! In [3]: id(a), id(b) # es wurde kein neuer Speicher angelegt... Out[3]: (2187003088144, 2187003088144) In [4]: b = 265 # belege Speicher mit Zahl und verknuepfe mit b In [5]: id(a), id(b) # Kopie da neuer Speicher angelegt ... Out[5]: (2187003088144, 2187003088624) * veränderbar: Trotz Wertzuweisung bleibt der Speicherplatz der Gleiche d.h. :mark:`typisches Zeigerverhalten`. Daher :mark:`Vorsicht, bei Listen, Dictionaries,...`:: In [1]: a = [1,2,3] # definiere a In [2]: b = a # b zeigt auf a In [3]: b[1]=5 # b noch immer Zeiger, aendert auch a! In [4]: b Out[4]: [1, 5, 3] # Veraenderung von b In [5]: a Out[5]: [1, 5, 3] # AUCH Veraenderung von a! Abhilfe schafft hier nur :mark:`explizites Kopieren`: :: In [1]: a = [1,2,3] In [2]: b=a[:] # explizites Kopieren In [3]: b[1]=5 In [4]: b Out[4]: [1, 5, 3] # Veraenderung von b In [5]: a Out[5]: [1, 2, 3] # keine Veraenderung von a NoneType ~~~~~~~~ In Python kann eine Variable : * noch nicht definiert sein * über eine Wertzuweisung :mark:`Name + Wert (Typ)` haben * oder den Typ ``None`` besitzen Beispiele: :: In [1]: b # Variable nicht definiert Traceback (most recent call last): File "", line 1, in b NameError: name 'b' is not defined In [2]: b = None # Variable definiert mit dem Wert "nichts" In [3]: b # keine Ausgabe nach ENTER! In [4]: b = 2 In [5]: b # Variable definiert, Wert = 2 Out[5]: 2 Dieser ``None`` Typ kann sehr hilfreich sein, z.B. beim Setzen von Defaultwerten (genaueres später). Bezeichner (identifiers) ~~~~~~~~~~~~~~~~~~~~~~~~ Darunter versteht man die :mark:`zulässigen Variablennamen`: :: identifiers ::= (letter | "_") (letter | digit | "_") letter ::= "a"..."z" | "A"..."Z" digit ::= "0"..."9" dabei heißt ``::=`` definiert als, ``|`` heißt oder. Beispiele für Bezeichner: :: In [1]: Karl93 = 39 # ok In [2]: _name3 = 'Susi' # ok In [3]: 12Sigma = 4.34 # nicht erlaubt! File "", line 1 12Sigma = 4.34 # nicht erlaubt! ^ SyntaxError: invalid syntax **Unterstriche** Unterstriche haben teilweise :mark:`"magisches Verhalten"` wie * doppelte Unterstriche (z.B. ``__doc__``, ``__init__``) * ein Unterstrich bei Klassendefinitionen (z.B. ``_name``) mehr dazu später. **Reservierte Namen** Wie in jeder Programmiersprache gibt es auch in Python reservierte Schlüsselwörter welche nicht als Bezeichner verwendet werden dürfen. :: False class finally is return None continue for lambda try True def from nonlocal while and del global not with as elif if or yield assert else import pass break except in raise Wahrheitswerte ============== Wahrheitswerte sind Variablen mit zwei Zuständen (0/1, wahr/falsch). Für diese gilt: * Literale in Python sind ``True`` oder ``False``. * Man kennt diese als Datentyp ``bool``. * In Python sind die Werte ``1``/``True`` bzw. ``0``/``False`` zugeordnet. Beispiele: :: In [1]: 12 > 11 Out[1]: True In [2]: antwort = ( 2*3 == 6 ) In [3]: antwort Out[3]: True In [4]: type(antwort) Out[4]: bool In [5]: antwort + antwort Out[5]: 2 Ganze Zahlen ============ Ganze Zahlen sind :mark:`positive oder negative Zahlen`. Für diese gilt: * diese können Dezimal-, Oktal-, Hexadezimal-, Binärzahlen sein. * und sind bekannt als Datentyp ``int`` (Integer). Beispiele: :: In [1]: 127 # Dezimalzahl Out[1]: 127 In [2]: 0b11011 # Binärzahl beginnt mit 0b Out[2]: 27 In [3]: 0x1af # Hexadezimalzahl beginnt mit 0x Out[3]: 431 Beachte: Die :mark:`Ausgabe` der Zahlen erfolgt immer als ganze :mark:`Dezimalzahl`. Gleitkommazahlen ================ Gleitkommazahlen sind positive oder negative :mark:`Zahlen mit einem "Komma"`. Für diese gilt: * Darstellung als Gleitkommazahlen ``31.4``, ``-0.00673`` * oder Exponentialzahl ``0.314E+2``, ``-673.e-05`` und * sind bekannt als Datentyp ``float``. Beispiele: :: In [1]: 12398741634341798.132 Out[1]: 1.2398741634341798e+16 In [2]: 0.0000000000234234 Out[2]: 2.34234e-11 Komplexe Zahlen =============== Komplexe Zahlen bestehen aus einem :mark:`Real- und Imaginärteil`. Für diese gilt: * Imaginärteil wird mit dem Suffix ``j`` oder ``J`` angegeben. * Anteile einer komplexen Zahl :mark:`z` werden ausgewählt mit: ``z.real`` und ``z.imag`` . * Diese sind bekannt als Datentyp ``complex``. Beispiele: :: In [3]: a = 2 + 3j In [4]: b = 1 - 1j In [5]: c = a*b In [6]: c Out[6]: (5+1j) In [7]: c.real Out[7]: 5.0 In [8]: c.imag Out[8]: 1.0 Operatoren für Zahlen ===================== **Arithmetische Operatoren** :: In [1]: -1 # negatives Vorzeichen Out[1]: -1 In [2]: +1 # positives Vorzeichen Out[2]: 1 In [3]: 2 + 3 # Addition Out[3]: 5 In [4]: 2 - 3 # Subtraktion Out[4]: -1 In [5]: 2.0 * 3 # Multiplikation Out[5]: 6.0 In [6]: 3 / 2 # Division Out[6]: 1.5 In [7]: 5 // 3 # Ganzzahldivision Out[7]: 1 In [8]: 5 % 3 # Rest einer Ganzzahldivision Out[8]: 2 In [9]: 2 ** 3 # Potenz Out[9]: 8 In [10]: 4 ** (1/3.) # Wurzel Out[10]: 1.5874010519681994 .. note:: Zahlentypen werden durch Operation verändert. Aus ``float`` wird ``int`` oder umgekehrt je nach Rechenoperation! **Boolsche Operatoren** :: In [1]: 2 > 1 # größer als, "<" kleiner als Out[1]: True In [2]: 3 >= 4 # größer gleich als Out[2]: False In [3]: 3 == 4 # vergleicht beide Werte "gleich", Achtung Out[3]: False In [4]: 3 != 4 # vergleicht beide Werte "nicht gleich" Out[4]: True Achtung die Operation ``==`` (vergleicht Werte) entspricht nicht ``is`` (vergleicht Identifier id(..)). Beispiel: :: In [1]: a = [5] In [2]: b = [5] In [3]: a is b # Listen haben unterschiedliche Identifier id(..) Out[3]: False In [4]: a == b # aber gleichen Wert Out[4]: True In [5]: a = b # a und b "zeigen" jetzt auf gleichen Speicherplatz In [6]: a is b # und haben deshalb den gleichen Identifier id(..) Out[6]: True In [7]: a == b # und natuerlich den gleichen Wert Out[7]: True **Kombination aus Zuweisung und Operator** :: In [1]: a = 2 # a ist 2 In [2]: a += 1 # addiere 1 zu a (ergibt 3), setze Ergebnis auf a In [3]: a Out[3]: 3 In [4]: a *= 2 # 2 mal a, setze neues Ergebnis auf a In [5]: a Out[5]: 6 In [6]: a -= 2 # -2 zu a, setze neues Ergebnis In [7]: a Out[7]: 4 Sequenzen ========= Sequenzen sind eine :mark:`Kollektion` einer Folge von :mark:`Objekten` (Elemente oder engl. items). Eigenschaften: * Jedes Element besitzt einen :mark:`Index` (Start bei 0, Letztes -1). * Typische Datentypen: *Listen*, *Tuple*, *Strings* * Abbildung `Graphische Darstellung einer Sequenz`_ zeigt eine Sequenz grafisch: .. _`Graphische Darstellung einer Sequenz`: .. figure:: images/sequenz.png :scale: 60 % :align: center Graphische Darstellung einer Sequenz **Methoden** Vorab einige Beispiele: :: In [1]: s = "Dies ist unser Teststring" In [2]: 'u' in s # prueft ob 'u' in Sequenz enthalten ist Out[2]: True In [3]: s += " mit Punkt." # Verkettung beider Sequenzen In [4]: s[2:8] # Ausschnitt von Index 2 bis 8 (exklusive) Out[4]: 'es ist' In [5]: len(s) # Laenge der Sequenz, Anzahl der Elemente Out[5]: 36 Für alle sequenziellen Datentypen sind folgende Operationen definiert (siehe Tabelle `Methoden von Sequenzen`_). In dieser Tabelle gilt: * s und t sind Instanzen desselben sequenziellen Datentyps (z.B. Liste, String, ...). * i, j, k und n sind Ganzzahlen (z.B. 1,2,3). * x ist eine Referenz auf eine beliebige Instanz des sequenziellen Datentyps (z.B. Ganzzahl, Buchstabe) .. _`Methoden von Sequenzen`: .. table:: Methoden von Sequenzen ================== ====================================================================================================== Notation Beschreibung ================== ====================================================================================================== x in s Prüft, ob x in s enthalten ist. Das Ergebnis ist eine bool-Instanz. x not in s Prüft, ob x nicht in s enthalten ist. Das Ergebnis ist eine bool-Instanz. Gleichwertig mit not x in s. s + t Das Ergebnis ist eine neue Sequenz, die eine Verkettung von s und t enthält. s += t Erzeugt die Verkettung von s und t und weist diese s zu. s\*n oder n\*s Liefert eine neue Sequenz, die die Verkettung von n Kopien von s enthält. s\*= n Erzeugt das Produkt s\*n und weist dieses s zu. s[i] Liefert das i-te Element von s. s[i:j] Liefert den Ausschnitt aus s von i bis j. s[i:j:k] Liefert den Ausschnitt aus s von i bis j, wobei nur jedes k-te Element beachtet wird. len(s) Gibt eine Ganzzahl zurück, die die Anzahl der Elemente von s angibt. min(s) Liefert das kleinste Element von s, sofern eine Ordnungsrelation für die Elemente definiert ist. max(s) Liefert das größte Element von s, sofern eine Ordnungsrelation für die Elemente definiert ist. ================== ====================================================================================================== Liste ~~~~~ Listen sind: * :mark:`veränderbare` (mutable) Sequenzen * können :mark:`beliebige` Datentypen enthalten (auch Listen) * werden in :mark:`eckige Klammern` gesetzt ``[`` .. ``]`` Beispiele: :: In [1]: [1,2,3,4] # Definition der Liste aus Zahlen Out[1]: [1, 2, 3, 4] In [2]: namen = ['Hans', 'Karl', 'Franz'] # Definition der Liste aus Strings In [3]: print(namen) ['Hans', 'Karl', 'Franz'] In [4]: print(len(namen), namen[1]) # Sequenzmethoden, siehe oben 3 Karl In [5]: position = ["A", [0.3, 1.4, 2.6]] # Gemischte Liste **Methoden** In der folgenden Tabelle sind s und t Listen, i, j und k sind Ganzzahlen. x ist eine beliebige Instanz. :mark:`Die eckigen Klammern` ``[ ]`` :mark:`in der Tabelle bedeuten, dass dieser Eintrag optional ist` (siehe Tabelle `Methoden von Listen`_). .. _`Methoden von Listen`: .. table:: Methoden von Listen ========================== ========================================================================================================================================== Methode Wirkung ========================== ========================================================================================================================================== s.append(x) Hängt Element x ans Ende von s an. s.extend(t) Hängt alle Elemente von t ans Ende von s an. s.count(x) Gibt an, wie oft das Element x in s vorkommt. s.index(x[, i[, j]]) Gibt den Index k des ersten Vorkommens von x im Bereich i <= k < j zurück. s.insert(i, x) Fügt x an der Stelle i in s ein. Anschließend hat s[i] den Wert von x, wobei alle folgenden Elemente um eine Stelle nach hinten aufrücken. s.pop([i]) Gibt das i-te Element von s zurück und entfernt es aus s. Ist i nicht angegeben, wird das letzte Element genommen. s.remove(x) Entfernt das erste Vorkommen von x aus der Sequenz s. s.reverse() Kehrt die Reihenfolge der Elemente in s um. s.sort() Sortiert s. ========================== ========================================================================================================================================== Weitere Beispiele: :: In [1]: l = [1, 2, 3] In [2]: l.extend([2, 4, 6]) In [3]: l Out[3]: [1, 2, 3, 2, 4, 6] In [4]: l.count(2) Out[4]: 2 In [5]: l.index(3) Out[5]: 2 In [6]: l.pop() Out[6]: 6 In [7]: l Out[7]: [1, 2, 3, 2, 4] In [8]: l.sort() In [9]: l Out[9]: [1, 2, 2, 3, 4] Bei Listen können auch alle `Methoden von Sequenzen`_ verwendet werden. Zeichenketten (Strings) ~~~~~~~~~~~~~~~~~~~~~~~ Zeichenketten sind: * Folgen von Zeichen (characters) * nicht änderbar (z.B. keine Zeichen entfernbar) * kurze Zeichenketten starten mit ``"`` oder ``'`` * lange Zeichenketten starten mit ``"""`` * können mit ``+`` zusammengesetzt werden * bekannt als Datentyp ``str`` (string) Beispiele: :: In [1]: name = "Hans Mayer" In [2]: name Out[2]: 'Hans Mayer' In [3]: name = "Hans \ ...: Mayer" In [4]: name Out[4]: 'Hans Mayer' In [5]: name = """Hans ...: Mayer""" In [6]: name Out[6]: 'Hans\nMayer' In [7]: type(name) Out[7]: str Bei Zeichenketten können auch alle `Methoden von Sequenzen`_ verwendet werden. **Steuerzeichen** Tabelle `String Steuerzeichen`_ fasst typische Steuerzeichen speziell für Zeichenketten zusammen. .. _`String Steuerzeichen`: .. table:: String Steuerzeichen =============== ================================================================================ Escape-Sequenz Bedeutung =============== ================================================================================ \\f Formfeed (FF) erzeugt einen Seitenvorschub. \\n Linefeed (LF) setzt die Ausgabeposition in die nächste Zeile. \\r Carriage Return (CR) setzt die Ausgabeposition an den Anfang der nächsten Zeile. \\t Horizontal Tab (TAB) hat die gleiche Bedeutung wie die Tabulatortaste. \\" Doppeltes Hochkomma \\' Einfaches Hochkomma \\ \\ Backslash, der wirklich als solcher in dem String erscheinen soll =============== ================================================================================ Beispiele: :: In [1]: print("Ein Satz\n mit Zeilenumbruch") Ein Satz mit Zeilenumbruch In [2]: print("Sonderzeichen: \\ \" \' u\x40") Sonderzeichen: \ " ' u@ **Methoden** In der Tabelle `String Methoden`_ sind s,t und u strings, i, j und k sind Ganzzahlen. x ist eine beliebige Instanz. Die eckigen Klammern ``[ ]`` bedeuten dass dieser Eintrag optional ist. .. _`String Methoden`: .. table:: String Methoden ======================== =================================================================================================================== Methode Wirkung ======================== =================================================================================================================== s.splitlines() Spaltet einen String in seine einzelnen Zeilen. Trennzeichen sind ``\n`` (Unix), ``\n\r`` (Win), ``\r`` (Mac). s.split([x[,i]]) Zerteilt einen String mittels x und gibt eine Liste zurück. i begrenzt die Anzahl der Trennungen. Siehe auch ``rsplit``. s.find(x[, i[, j]]) Gibt den Index k des ersten Vorkommens von x im Bereich i <= k < j zurück. Gib -1 zurück wenn x nicht vorkommt.. Siehe auch ``rfind``. s.count(x) Gibt an, wie oft das Element x in s vorkommt. s.replace(t, u[, i]) Ersetzt in s den String t durch String u. Mit i wird die Anzahl, wie oft t durch u ersetzt wird, begrenzt. s.lower() Alle Buchstaben klein schreiben. s.upper() Alle Buchstaben groß schreiben. s.strip() Entfernt unerwünschte Zeichen auf beiden Seiten von s. Siehe auch ``lstrip``, ``rstrip``. s.isalpha() True, wenn alle Zeichen in s Buchstaben sind. s.isdigit() True, wenn alle Zeichen in s Ziffern sind. s.islower() True, wenn alle Buchstaben in s Kleinbuchstaben sind. Siehe auch ``isupper``, ``isspace``. ======================== =================================================================================================================== Beispiele: :: In [1]: s = "Unix\nWindows\r\nMac\rLetzte Zeile" In [2]: s.splitlines() Out[2]: ['Unix', 'Windows', 'Mac', 'Letzte Zeile'] In [3]: s = "Dieser String wird durchsucht" In [4]: s.split() Out[4]: ['Dieser', 'String', 'wird', 'durchsucht'] In [5]: s.split("e") Out[5]: ['Di', 's', 'r String wird durchsucht'] In [6]: s.find("haha") Out[6]: -1 In [7]: s.find("w") Out[7]: 14 In [8]: s.count("e") Out[8]: 2 In [9]: s.replace("wird","wurde") Out[9]: 'Dieser String wurde durchsucht' In [10]: s.lower() Out[10]: 'dieser string wird durchsucht' In [11]: s.upper() Out[11]: 'DIESER STRING WIRD DURCHSUCHT' In [12]: s = " \t\n \rUmgeben von Whitespaces \t\t\r" In [13]: s.strip() Out[13]: 'Umgeben von Whitespaces' **Formatierung** Darunter versteht man die :mark:`Anpassung der (Bildschirm)ausgaben` auf bestimmte Art und Weise. Am besten erklärt man dies an einem Beispiel:: In [1]: h=13; m=37 In [2]: "Es ist "+str(h)+":"+str(m)+" Uhr." # klassisch, umständlich Out[2]: 'Es ist 13:37 Uhr.' In [3]: f"Es ist {h}:{m} Uhr." # f-string Methode Out[3]: 'Es ist 13:37 Uhr.' In [4]: x = 123.4567 In [5]: f"Gleitkommazahl {x}" Out[5]: 'Gleitkommazahl 123.4567' In [6]: f"Gleitkommazahl {x/3:8.2f}" # 8 Zeichen, 2 nach dem Komma Out[6]: 'Gleitkommazahl 41.15' Diese Methode heißt :mark:`f-string` (vorangestelltes ``f``) und führt zu einer entsprechenden Auswertung von Ausdrücken, Umwandlung von Variablen und Formatierung des Ausgabestrings. Diese Methode ist ab Python 3.6 verfügbar. :mark:`Mathematische Ausdrücke` innerhalb geschwungenen Klammern werden ausgewertet. Der ``:`` innerhalb der geschwungenen Klammern ermöglicht die Ausgabe weiter zu formatieren. d.h. ``Wert:Laenge.Genauigkeit`` wobei die ``Laenge`` die gesamte Anzahl der Zeichen darstellt und die ``Genauigkeit`` die Anzahl der werttragenden Stellen. Einige wichtige Ausgabedatentypen finden sich in Tabelle `String Ausgabedatentypen`_. .. _`String Ausgabedatentypen`: .. table:: String Ausgabedatentypen ============ ========================================================================================================== Kennung Beschreibung ============ ========================================================================================================== E, e Fließkommazahl im wissenschaftlichen Format (großes E oder kleines e) f Fließkommazahl in Dezimalschreibweise g, G Fließkommazahl in wissenschaftlicher Schreibweise, wenn Exponent kleiner als –4, sonst Dezimalschreibweise ============ ========================================================================================================== Beispiele: :: In [1]: a=0.00034545 In [2]: f"Exponential Schreibweise:{a:16E}" Out[2]: 'Exponential Schreibweise: 3.454500E-04' # 16 Zeichen In [3]: # 1234567890123456 -> 16 Zeichen In [4]: f"Wissenschaftliche Schreibweise:{a:g}" Out[4]: 'Wissenschaftliche Schreibweise:0.00034545' In [5]: f"Wissenschaftliche Schreibweise:{a:12.3g}" # 12 Zeichen, 3 werttragende Stellen Out[5]: 'Wissenschaftliche Schreibweise: 0.000345' In [6]: f"Wissenschaftliche Schreibweise:{a:.3g}" # 3 werttragende Stellen Out[6]: 'Wissenschaftliche Schreibweise:0.000345' In [7]: f"Wissenschaftliche Schreibweise:{a/100:.3g}" # autom. Wechsel zu 'e' Schreibweise Out[7]: 'Wissenschaftliche Schreibweise:3.45e-06' Tupel ~~~~~ Tupel sind: * lt. Python :mark:`unveränderbare` Sequenzen (stimmt nicht ganz ..) * können :mark:`beliebige` Datentypen enthalten * werden in runde Klammern gesetzt ``(`` .. ``)`` Beispiele: :: In [1]: (2.3, 5.3, 6.2) Out[1]: (2.3, 5.3, 6.2) In [2]: adresse = ("Hans", "Mayer", 63) .. note:: im Prinzip können :mark:`Listen` alles was Tupel können. Deshalb gehen wir nicht näher darauf ein. Mengen ====== Set ~~~ Sets sind :mark:`klassische Mengen` aus der Mathematik: Diese: * kennen keine :mark:`doppelten` Einträge (nicht wie bei Listen), * werden in geschwungene Klammern gesetzt ``{`` .. ``}``, * erlauben Operatoren wie Durchschnitt ``&``, Vereinigung ``|`` und Differenz ``-``. Beispiele: :: In [1]: a = {1, 3, 3, 4} In [2]: a Out[2]: {1, 3, 4} In [3]: type(a) Out[3]: set In [4]: b = set( [4, 6, 8] ) # Initialisierung mittels Liste In [5]: a & b Out[5]: {4} In [6]: a | b Out[6]: {1, 3, 4, 6, 8} In [7]: a - b Out[7]: {1, 3} Mappings ======== Dictionary ~~~~~~~~~~ Dictionaries sind :mark:`Wörterbücher`. Ein sehr mächtiges und hilfreiches Datenkonzept: Dictionaries in Python: * haben Einträge aus :mark:`Werte-Paaren` d.h. Schlüsselwort/Wert (key/value) * können Zahlen, Strings, etc als Schlüsselwort haben und * erlauben ein :mark:`schnelles Suchen` nach dem Schlüsselwort. * Auch bekannt als :mark:`map` (C++) oder :mark:`associative array`. Beispiele: :: In [1]: woerterbuch = {"Germany" : "Deutschland", "Spain" : "Spanien"} In [2]: type(woerterbuch) Out[2]: dict In [3]: woerterbuch["Germany"] Out[3]: 'Deutschland' In [4]: for key in woerterbuch: ...: print(key) ...: Germany Spain **Operatoren** In Tabelle `Dictionary Operatoren`_ ist ``d`` ein Dictionary und ``k`` der "key". .. _`Dictionary Operatoren`: .. table:: Dictionary Operatoren =============== ============================================================== Operator Beschreibung =============== ============================================================== len(s) Liefert die Anzahl aller im Dictionary s enthaltenen Elemente. d[k] Zugriff auf den Wert mit dem Schlüssel k del d[k] Löschen des Schlüssels k und seines Wertes k in d True, wenn sich der Schlüssel k in d befindet =============== ============================================================== Fortsetzung des obigen Beispiels: :: In [5]: woerterbuch["French"] = "Frankreich" In [6]: woerterbuch Out[6]: {'Germany': 'Deutschland', 'Spain': 'Spanien', 'French': 'Frankreich'} In [7]: len(woerterbuch) Out[7]: 3 In [8]: del woerterbuch["Germany"] In [9]: "Germany" in woerterbuch Out[9]: False **Methoden** Tabelle `Dictionary Methoden`_ fasst die wichtigsten Zugriffsfunktionen zusammen. .. _`Dictionary Methoden`: .. table:: Dictionary Methoden =================== =========================================================================================================================================== Methode Beschreibung =================== =========================================================================================================================================== d.clear() Löscht den Inhalt des Dictionarys d. Das Dictionary selbst bleibt bestehen. d.copy() Erzeugt eine Kopie von d. Beachten Sie, dass nur das Dictionary selbst kopiert wird. Alle Werte bleiben Referenzen auf dieselben Instanzen. d.items() Erzeugt eine Liste, die alle Schlüssel/Wert-Paare von d als Tupel enthält. d.keys() Erzeugt eine Liste aller Schlüssel von d. d.values() Erzeugt eine Liste aller Werte von d. =================== =========================================================================================================================================== Fortsetzung des obigen Beispiels: :: In [10]: woerterbuch Out[10]: {'Spain': 'Spanien', 'French': 'Frankreich'} In [11]: woerterbuch.items() Out[11]: dict_items([('Spain', 'Spanien'), ('French', 'Frankreich')]) In [12]: woerterbuch.keys() Out[12]: dict_keys(['Spain', 'French']) In [13]: woerterbuch.values() Out[13]: dict_values(['Spanien', 'Frankreich']) In [14]: w2 = woerterbuch In [15]: id(w2), id(woerterbuch) # Zeiger, gleiches Woerterbuch Out[15]: (2457905266424, 2457905266424) In [16]: w2 = woerterbuch.copy() # Kopie In [17]: id(w2), id(woerterbuch) Out[17]: (2457905783576, 2457905266424) In [18]: id(w2['Spain']) # aber Values haben gleiche Id Out[18]: 2457905543600 In [19]: id(woerterbuch['Spain']) Out[19]: 2457905543600 In [20]: w2['Spain'] = "Irgendwas" # bis Values veraendert werden In [21]: w2 Out[21]: {'Spain': 'Irgendwas', 'French': 'Frankreich'} In [22]: woerterbuch Out[22]: {'Spain': 'Spanien', 'French': 'Frankreich'} In [23]: id(w2['Spain']) Out[23]: 2457905852464 In [24]: id(woerterbuch['Spain']) Out[24]: 2457905543600 In [20]: w2.clear() In [21]: w2 Out[21]: {} Typumwandlungen =============== In bestimmten Situation besteht die Notwendigkeit den :mark:`Datentyp` während der Laufzeit zu :mark:`wechseln`. **Methoden** Tabelle `Typumwandlungen Methoden`_ fasst diese zusammen. .. _`Typumwandlungen Methoden`: .. table:: Typumwandlungen Methoden =============== ======================================================================== Methode Beschreibung =============== ======================================================================== float(x) Erzeugt aus x eine Gleitkommazahl. int(x) Erzeugt aus x eine Ganzzahl. str(x) Erzeugt aus x einen String. bool(x) Erzeugt aus x einen Wahrheitswert. dict(x) Erzeugt aus x ein Dictionary sofern x aus einer Liste von Paaren besteht list(x) Erzeugt aus x eine Liste. =============== ======================================================================== Beispiele: :: In [1]: a = "123" In [2]: float(a) Out[2]: 123.0 In [3]: b = 435.2 In [4]: int(b) Out[4]: 435 In [5]: bool(b) Out[5]: True In [6]: str(b) Out[6]: '435.2' In [7]: c = [(3,'drei'),(4,'vier')] In [8]: dict(c) Out[8]: {3: 'drei', 4: 'vier'} In [9]: list( dict(c) ) Out[9]: [3, 4] Übungsbeispiele ==================== **Aufgabe 3.1** Veränderbare vs. unveränderbare Datentypen: 1) Definieren Sie eine Zahl ``a`` mit beliebigem Wert. 2) Definieren Sie eine weitere Variable ``b``, die auf ``a`` verweist. Überprüfen Sie ob es sich bei ``a`` und ``b`` um das selbe Objekt handelt, d.h. ob die Speicheradresse von ``a`` und ``b`` gleich ist. 3) Addieren Sie ``1`` zu ``b``. Hat sich ``a`` dadurch verändert? Hat sich die Speicheradresse von ``b`` verändert? Sind Zahlen in python daher veränderlich oder unveränderlich? 4) Definieren Sie eine beliebige Liste ``liste_a``. 5) Definieren Sie eine weitere Liste ``liste_b``, die auf ``liste_a`` verweist. Überprüfen Sie ob es sich bei ``liste_a`` und ``liste_b`` um das selbe Objekt handelt, d.h. ob die Speicheradresse von ``liste_a`` und ``liste_b`` gleich ist. 6) Addieren Sie ``1`` zum ersten Element von ``liste_b``. Verändert sich ``liste_a`` dadurch. Was ist mit den Speicheradressen? Sind Listen in python daher veränderlich oder unveränderlich? 7) Wiederholen Sie Punkt 5) und 6) wobei ``liste_b`` jetzt als explizite Kopie von ``liste_a`` definiert wird. Was verändert sich? 8) Definieren Sie eine beliebige Liste von Listen ``liste``, d.h. eine Liste, die mehrere Listen enthält. Legen Sie eine explizite Kopie der ``liste`` an. Sie können überprüfen, ob eine neue Liste angelegt wurde, indem Sie z.B. ``1`` zum ersten Element der innersten Liste addieren und überprüfen, dass sich die ursprüngliche Liste dabei nicht verändert. **Aufgabe 3.2** Gegeben sei ein String welcher Gleitkommazahlen enthält, zum Beispiel: ``4.52 ; 1.23;8.65; 1.4`` 1) Extrahieren Sie die Gleitkommazahlen und fügen Sie sie in eine Liste ``Zahlenstrings`` ein. 2) Konvertieren Sie die Elemente aus ``Zahlenstrings`` auf den Datentyp ``float``. Fügen Sie die Zahlen in eine Liste ``Gleitkommazahlen`` ein. 3) Berechnen Sie das Maximum der Liste und geben Sie es mit einer Nachkommastelle aus. 4) Runden Sie die Gleitkommazahlen auf Ganzzahlen ab (z.B. 1.23 ergibt 1, 8.65 ergibt 8). Fügen Sie die Zahlen in eine Liste ``Ganzzahlen`` ein. * Prüfen Sie ob die Zahl 1 in der Liste vorkommt. * Wenn ja, wie oft und an welcher Stelle der Liste kommt sie vor? 5) Erzeugen Sie ein Dictionary bei dem die Ganzzahl das Schlüsselwort und die Gleitkommazahl den Wert darstellt. Was passiert wenn Sie zweimal die gleiche Ganzzahl als Schlüssel verwenden? 6) Geben Sie den Schlüssel sowie den Wert des Dictonaries im Format ``Schluessel=..., Wert=...`` in der Konsole aus. weitere Übungsbeispiele ================= **Aufgabe 3.3** 1) Erzeuge ein Python Skript mit beliebigem Namen mittels Spyder. 2) Definiere darin zwei Variablen: Variable ``Laenge`` mit Wert "3" und Variable ``Breite`` mit Wert "7.43". 3) Berechne das Produkt beider Variablen (=Fläche) und gib es am Bildschirm mit ``print`` aus d.h. erstelle den Quellcode in Spyder und führe das Skript aus. 4) Erzeuge eine Stringvariable ``Antwort`` mit dem Wert ``"Ergebnis: Flaeche ="``. Verbessere die vorhergehende Ausgabe indem du die Länge und Breite sowie die Fläche mit der Variable ``Antwort`` ausgibst. Beispiel Ausgabe: :: Berechnungsergebnis -------------------------- Laenge = 3 Breite = 7.43 Ergebnis: Flaeche = 22.29 5) Überprüfe den Datentyp, die Speicherplatznummer und den Wert aller bislang erzeugten Variablen indem du diese am Bildschirm mit ``print`` ausgibst. Versuche die Ausgabe selbsterklärend zu gestalten d.h. :: Datentypen -------------------------- Laenge Datentyp = Identitaet = 14385448 Wert = 3 6) Speichere die beiden Variablen in einer neu erzeugten Liste mit dem Namen ``DatenListe``. Verwende dazu ``append``. Überprüfe den Inhalt und Anzahl der Elemente welche sich in der Liste befinden z.B. mittels ``print``. 7) Berechne wie zuvor das Produkt beider Variablen indem du die Werte aus der Liste liest. Gibt das Ergebnis wie zuvor am Bildschirm aus. Die Ausgabe sollte selbsterklärend sein z.B. :: Liste -------------------------- Inhalt = [3, 7.43] Anzahl = 2 Flaeche = 22.29 8) Speichere die beiden Variablen (``Laenge`` und ``Breite``) in einem neu erzeugten Dictonary ``DatenDict`` ab. Der Variablenname (Zeichenkette) dient dabei als Schlüssel. 9) Bereche wie zuvor das Produkt beider Variablen (=Fläche) mit Hilfe der Werte aus dem Dictionary. Speichere das Ergebnis in das Dictonary ``DatenDict`` unter dem Schlüssel ``Flaeche`` ab. 10) Erzeuge die gleiche Ausgabe wie bei der Liste mit den Ausgaben Inhalt, Anzahl, Flaeche (Ausgabe siehe oben). 11) Überprüfe ob sich der Schlüssel ``Flaeche`` im Dictonary ``DatenDict`` befindet. 12) Gib die Fläche aus ``DatenDict`` am Bildschirm mit 10 Digits und 3 Nachkommastellen in der Form :: Flaeche = 22.290 aus. 13) Wandle die Variable ``Breite`` in eine Ganzzahl um. Berechne damit die Fläche und gib diese aus. Warum hat sich die Fläche verändert? .. hint :: Versuche das Skript alleine oder gemeinsam in einer Gruppe zu erstellen ohne einer Vorlage. Nur so lernt man Programmieren. Das gesamte Skript zu diesen vielen Fragen hat weniger als 50 Zeilen! Frage bei den Übungen falls etwas nicht klar ist. Unsere Erfahrung zeigt: Wer diese Aufgabe nicht selbst programmiert und die Hintergründe versteht, schafft das erste Kolloquium im Allgemeinen nicht. Beachte auch dass der folgende Stoff auf diesen Inhalten aufbaut! **Aufgabe 3.4** Volumen eines Kegels: 1) Definieren Sie eine Liste, die 3 strings enthält: ``" r = 1.33"``, ``"h = 4.5"`` und ``"pi=3.1415"``. Hierbei ist r der Radius der Grundfläche eine Kegels, h seine Höhe und pi die mathematische Konstante π. 2) Extrahieren Sie die Zahlenwerte aus den Strings der Liste und speichern Sie sie in den Variablen ``r``, ``h`` und ``pi`` ab. Achten Sie darauf, dass die Strings beliebige Zahlen mit beliebig vielen Leerzeichen beinhalten können! 3) Berechnen Sie das Volumen des Kegels und geben Sie das Ergebnis per print Befehl aus. Hinweis: .. math :: V_{\mathrm{Kegel}} = \frac{1}{3} \cdot r^2 \cdot \pi \cdot h 4) Erstellen Sie ein Dictionary ``Kegel``, das die Variablen ``r``, ``h`` und ``pi`` mit ihren jeweiligen Zahlenwerten enthält. Dabei soll der jeweilige Variablenname als string der Schlüssel sein. Für den Wert wird der jeweilige Zahlenwert als Gleitkommazahl zugeordnet. 5) Errechnen Sie das Volumen erneut. Verwenden Sie diesmal jedoch das Dictionary ``Kegel`` für die Berechnung. Geben Sie das Ergebnis erneut per print Befehl aus. **Aufgabe 3.5** Gegeben ist eine Zeichenkette mit den Einträgen ``1, zwei, 3, 4.12``. 1) Erstellen Sie eine Liste, die die durch Beistriche getrennten Elemente des Strings enthält. * Entfernen Sie überschüssige Leerzeichen am Ende und Anfang jedes Elements der Liste. * Konvertieren Sie in der Liste alle Strings, die Ganzzahlen sind zum Datentyp integer und alle Strings, die Gleitkommazahlen sind zum Datentyp float. Einträge, die keine Zahlen sind bleiben als Strings in der Liste. 2) Überprüfen Sie ob sich ``1`` bzw. ``e`` in dem String bzw. der Liste befindet. * Welchen Datentyp muss ``1`` haben um in dem String bzw. der Liste gefunden zu werden? * Überprüfen Sie zusätzlich ob ``e`` in den Elementen der Liste enthalten ist. 3) Geben Sie die Länge des Strings bzw. der Liste aus. 4) Hängen Sie ein beliebiges Element an das Ende von String bzw. Liste an. Geben Sie den veränderten String / die veränderte Liste aus. 5) Legen Sie eine Kopie des Strings / der Liste an und wiederholen Sie Punkt 4) für die Kopie. Achten sie darauf, dass sich die ursprünglichen Objekte nicht verändern!