.. 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 Kapitelen 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: :: >>> a # Wert der Variablen 342 >>> type(a) # Typ der Variablen >>> id(a) # Identität der Variablen 28609680 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 ein Ganzahl (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: :: >>> x = 15 # Typ int >>> x = 'Hansi' # Typ von int -> string >>> x / 2. Traceback (most recent call last): File "", line 1, in 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: :: >>> a = 342 # belege Speicher mit Zahl und erzeuge Zeiger a >>> b = a # zeige mit b auf a, b ist ein weiterer Zeiger! >>> id(a), id(b) # es wurde kein neuer Speicher angelegt... (10386576, 10386576) >>> b = 265 # belege Speicher mit Zahl und verknuepfe mit b >>> id(a), id(b) # Kopie da neuer Speicher angelegt ... (10386576, 10386480) * veränderbar: Trotz Wertzuweisung bleibt der Speicherplatz der Gleiche d.h. :mark:`typisches Zeigerverhalten`. Daher :mark:`Vorsicht, bei Listen, Dictionaries,...`:: >>> a = [1,2,3] # definiere a >>> b = a # b zeigt auf a >>> b[1]=5 # b noch immer Zeiger, aendert auch a! >>> b # b hat sich veraendert [1, 5, 3] >>> a # aber auch a hat sich veraendert! [1, 5, 3] Abhilfe schafft hier nur :mark:`explizites Kopieren`: :: >>> b=a[:] # explizites Kopieren >>> b [1, 2, 3] >>> b[1]=5 >>> b [1, 5, 3] # Veraenderung von b >>> a [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: :: >>> b # Variable nicht definiert Traceback (most recent call last): File "", line 1, in NameError: name 'b' is not defined >>> b = None # Variable definiert, Wert = nichts >>> b >>> # keine Ausgabe >>> b = 2 # Variable definiert, Wert = 2 >>> b 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: :: >>> Karl93 = 39 # ok >>> _name3 = 'Susi' # ok >>> 12Sigma = 4.34 # nicht erlaubt! File "", line 1 12Sigma = 4.34 ^ 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: :: >>> 12 > 11 True >>> antwort = ( 2*3 == 6 ) >>> antwort True >>> type(antwort) >>> antwort + antwort 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: :: >>> 127 # Dezimalzahl 127 >>> 0b11011 # Binärzahl beginnt mit 0b 27 >>> 0x1af # Hexadezimalzahl beginnt mit 0x 431 Beachte: Die :mark:`Ausgabe` der Zahlen erfolgt immer als ganze :mark:`Dezimalzahl`. Gleitkommazahlen ================ Gleitkommazahlen sind postive 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: :: >>> 12398741634341798.132 1.2398741634341798e+16 >>> 0.0000000000234234 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: :: >>> a = 2 + 3j >>> b = 1 - 1j >>> c = a*b >>> c (5+1j) >>> c.real 5.0 >>> c.imag 1.0 Operatoren für Zahlen ===================== **Arithmetische Operatoren** >>> -1 # negatives Vorzeichen -1 >>> +1 # positives Vorzeichen 1 >>> 2 + 3 # Addition 5 >>> 2 - 3 # Subtraktion -1 >>> 2.0 * 3 # Multiplikation 6.0 >>> 3 / 2. # Division, Achtung nicht 3 / 2 ! 1.5 >>> 5 // 3 # Ganzzahldivision 1 >>> 5 % 3 # Rest einer Ganzzahldivision 2 >>> 2 ** 3 # Potenz 8 >>> 4 ** (1/3.) # Wurzel 1.5874010 .. note:: Zahlentypen werden durch Operation verändert. Aus ``float`` wird ``int`` oder umgekehrt! .. warning:: Die Division ``/`` ist in Python 2 und Python 3 unterschiedlich. Ein kleiner Punkt macht den großen Unterschied! **Boolsche Operatoren** >>> 2 > 1 # größer als, "<" kleiner als True >>> 3 >= 4 # größer gleich als False >>> 3 == 4 # vergleicht Werte False >>> 3 is 4 # vergleicht den Identifier id(..) False >>> 3 != 4 # vergleicht Werte True >>> 3 is not 4 # vergleicht den Identifier id(..) True >>> True and False # logisches UND False >>> True or False # logisches ODER True **Kombination aus Zuweisung und Operator** >>> a = 2 # a ist 2 >>> a += 1 # 1 zu a (ergibt 3), setze Ergebnis auf a >>> a 3 >>> a *= 2 # 2 mal a, setze neues Ergebnis >>> a 6 >>> a -= 2 # -2 zu a, setze neues Ergebnis >>> a 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: :: >>> s = "Dies ist unser Teststring" >>> 'u' in s # Prueft ob 'u' in Sequenz enthalten ist True >>> s += " mit Punkt." # Verkettung beider Sequenzen 'Dies ist unser Teststring mit Punkt.' >>> s[2:8] # Ausschnitt von Index 2 bis 8 (exklusive) 'es ist' >>> len(s) # Laenge der Sequenz, Anzahl der Elemente 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: :: >>> [1,2,3,4] # Definition der Liste aus Zahlen [1, 2, 3, 4] >>> namen = ['Hans', 'Karl', 'Franz'] # Definition der Liste aus Strings >>> print namen ['Hans', 'Karl', 'Franz'] >>> print len(namen), namen[1] # Sequenzmethoden, siehe oben 3, Karl >>> 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: :: >>> l = [1, 2, 3] >>> l.extend([2, 4, 6]) >>> l [1, 2, 3, 2, 4, 6] >>> l.count(2) 2 >>> l.index(3) 2 >>> l.pop() 6 >>> l [1, 2, 3, 2, 4] >>> l.sort() >>> l [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: :: >>> name = "Hans Mayer" >>> name 'Hans Mayer' >>> name = "Hans \ ... Mayer" >>> name 'Hans Mayer' >>> name = """Hans ... Mayer""" >>> name 'Hans \nMayer' >>> type(name) 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: :: >>> print "Ein Satz\n mit Zeilenumbruch" Ein Satz mit Zeilenumbruch >>> 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. Siehe auch ``rcount``. 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: :: >>> s = "Unix\nWindows\r\nMac\rLetzte Zeile" >>> s.splitlines() ['Unix', 'Windows', 'Mac', 'Letzte Zeile'] >>> s = "Dieser String wird durchsucht" >>> s.split() ['Dieser', 'String', 'wird', 'durchsucht'] >>> s.split("e") ['Di', 's', 'r String wird durchsucht'] >>> s.find("haha") -1 >>> s.find("w") 14 >>> s.count("e") 2 >>> s.replace("wird","wurde") 'Dieser String wurde durchsucht' >>> s.lower() 'dieser string wird durchsucht' >>> s.upper() 'DIESER STRING WIRD DURCHSUCHT' >>> s = " \t\n \rUmgeben von Whitespaces \t\t\r" >>> s.strip() '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:: >>> "Es ist %d:%d Uhr" % (13, 37) # die Zahlen in Klammern ersetzen die %d Platzhalter 'Es ist 13:37 Uhr' >>> x = 123.45678 >>> "Gleitkommazahl %+10.2f" % x # 10 Digits, 2 nach dem Komma 'Gleitkommazahl +123.46' Dabei werden im String Platzhalter (``%d``, ``%+10.2f``) mit bestimmter Bedeutung angegeben. Der nachfolgende Ausdruck (nach dem ``%`` Zeichen) gibt die Werte an mit welchen aufgefüllt wird. Bei nur einem Platzhalter sind keine Klammern ``(..)`` notwendig. Einige wichtige Ausgabedatentypen finden sich in Tabelle `String Ausgabedatentypen`_. .. _`String Ausgabedatentypen`: .. table:: String Ausgabedatentypen ============ ===================================================================================================================== Kennung Beschreibung ============ ===================================================================================================================== %d Ganzzahl mit Vorzeichen %i Ganzzahl mit Vorzeichen %E Fließkommazahl im wissenschaftlichen Format (großes »E«) %f Fließkommazahl in Dezimalschreibweise %g Fließkommazahl in wissenschaftlicher Schreibweise, wenn der Exponent kleiner als –4 ist, sonst in Dezimalschreibweise %r String (macht aus jeder Instanz einen String mit der Builtin-Function ``repr``) %s String (macht aus jeder Instanz einen String mit der Builtin-Function ``str``) % Gibt ein Prozentzeichen aus ============ ===================================================================================================================== Eine Zahl zwischen ``%`` und der Kennung gibt an wieviel Zeichen (Digits) verwendet werden sollen. Beispiele: :: >>> "String mit 10 Zeichen:%10s" % "Haha" 'String mit 10 Zeichen: Haha' >>> "Exponentialzahl mit 13 Zeichen, 6 nach Komma:%13.6E" % 0.00034545 'Exponentialzahl mit 13 Zeichen, 6 nach Komma: 3.454500E-04' Tupel ~~~~~ Tupel sind: * lt. Python :mark:`unveränderbare` Sequenzen (stimmt nicht ganz ..) * können :mark:`beliebige` Datentypen enthalten * werden in runde Klammern gesetzt ``(`` .. ``)`` Beispiele: :: >>> (2.3, 5.3, 6.2) (2.3, 5.3, 6.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: :: >>> a = {1, 3, 3, 4} >>> a set([1, 3, 4]) >>> b = set( [4, 6, 8] ) # Initialisierung mittels Liste >>> a & b set([4]) >>> a | b set([1, 3, 4, 6, 8]) >>> a - b set([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: :: >>> woerterbuch = {"Germany" : "Deutschland", "Spain" : "Spanien"} >>> woerterbuch["Germany"] 'Deutschland' >>> 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: :: >>> woerterbuch["French"] = "Frankreich" >>> woerterbuch {'Germany': 'Deutschland', 'French': 'Frankreich', 'Spain': 'Spanien'} >>> len(woerterbuch) 3 >>> del woerterbuch["Germany"] >>> "Germany" in woerterbuch 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: :: >>> woerterbuch {'Germany': 'Deutschland', 'French': 'Frankreich', 'Spain': 'Spanien'} >>> woerterbuch.items() [('Germany', 'Deutschland'), ('French', 'Frankreich'), ('Spain', 'Spanien')] >>> woerterbuch.keys() ['Germany', 'French', 'Spain'] >>> woerterbuch.values() ['Deutschland', 'Frankreich', 'Spanien'] >>> w2 = woerterbuch >>> id(w2), id(woerterbuch) (22022112, 22022112) >>> w2 = woerterbuch.copy() >>> id(w2), id(woerterbuch) (22477008, 22022112) >>> id(w2["Germany"]) 139785289400800 >>> id(woerterbuch["Germany"]) 139785289400800 >>> w2.clear() >>> w2 {} 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: :: >>> a = "123" >>> float(a) 123.0 >>> b = 435.2 >>> int(b) 435 >>> bool(b) True >>> str(b) '435.2' >>> c = [(3,'drei'),(4,'vier')] >>> dict(c) {3: 'drei', 4: 'vier'} >>> list( dict(c) ) [3, 4] Übungsbeispiele 3 ==================== **\*Aufgabe 3.0** 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.1** 1) Erzeugen Sie ein Python Skript mit beliebigem Namen mittels Spyder. 2) Definieren Sie darin eine Zahl ``Intervall`` mit dem Wert ``314159``. ``Intervall`` gibt die Länge eines Zeitintervalls in Sekunden an. 3) Rechnen Sie ``Intervall`` in Stunden, Minuten und Sekunden um und speichern Sie die Ergebnisse in sinnvoll benannten Variablen ab. Verwenden Sie dazu die Operatoren für Ganzzahldivision und Rest einer Ganzzahldivision aus Kapitel 3.7. .. hint :: Überprüfen Sie immer die Richtigkeit Ihres Programms! Hier kann es z.B. hilfreich sein, andere Intervalllängen, z.B. ``1``, ``60``, ``3600``, etc. zu testen. Zum Testen können Sie z.B. auch aus den Stunden, Minuten und Sekunden wieder die Dauer in Sekunden berechnen. 4) Definieren Sie eine Liste ``Werte_Liste``, die alle bisher definierten Variablenwerte enthält. Prüfen Sie den Inhalt der Liste mittels ``print``. 5) Fügen Sie ``34`` ans Ende von ``Werte_Liste`` an. 6) Berechnen Sie zu einem Würfel mit Volumen ``34`` die Seitenlänge ``a``. Verwenden Sie dazu den Wert ``34`` vom Ende von ``Werte_Liste``. 7) Hängen Sie ``a`` ans Ende der Liste an. **Aufgabe 3.2** 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.3** Gegeben sei ein String welcher Gleitkommazahlen enthält, z.B. ``4.52;1.23;8.65;1.4`` 1) Extrahieren Sie die Gleitkommazahlen und konvertieren Sie diese auf den Datentyp ``float``. 2) Runden Sie die Gleitkommazahlen auf Ganzzahlen (z.B. 1.23 ergibt 1, 8.65 ergibt 9), z.B. mit der Funktion ``round(Zahl)``. 3) 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? 4) Geben Sie den Schlüssel sowie den Wert des Dictonaries im Format ``Schluessel=..., Wert=...`` in der Konsole aus. Hausaufgaben ============ .. **Hausaufgabe 2.1 (1 Punkt)** Gegeben ist eine Liste ``Preise`` mit den Einträgen ``1.50, 0.99, 12.40, 0.99, 15.25``. Schreiben Sie Code, der die folgenden Punkte löst und lassen Sie sich zu jedem Punkt eine kurze Ausgabe mit erklärendem Text ausgeben. 1) Finden Sie heraus ob sich die Zahl ``0.99`` in der Liste befindet. 2) Wenn ja, wie oft ist die Zahl ``0.99`` in der Liste enthalten? 3) Finden Sie alle Positionen, an denen sich ``0.99`` in der Liste befindet. Kontrollieren Sie, dass Sie die richtigen Stellen gefunden haben, indem Sie die Liste an diesen Positionen auslesen. 4) Entfernen Sie alle Vorkommen von ``0.99`` aus der Liste. 5) Hängen Sie die Zeichenkette ``leer`` an die Liste an. 6) Bestimmen Sie die aktuelle Länge der Liste. 7) Multiplizieren Sie die Liste mit ``2`` und überprüfen Sie das Ergebnis mittels ``print``. 8) Multiplizieren Sie jedes Element der Liste mit ``2``. 9) Erstellen Sie eine neue Liste ``Produkte`` mit beliebigen Einträgen. Addieren Sie die Listen ``Preise`` und ``Produkte``. 10) Erstellen Sie eine neue Liste ``Lager``, die die Liste ``Preise`` als 0. Element und die Liste ``Produkte`` als 1. Element enthält. D.h. ``Lager`` ist eine Liste, die Listen enthält. 11) Erstellen Sie eine explizite Kopie von ``Lager``. 12) Schreiben Sie mindestens 2 Tests um zu überprüfen, dass eine Veränderung an der Kopie die ursprüngliche Liste ``Lager`` tatsächlich nicht verändert. .. hint :: Überprüfen Sie nach jedem Punkt durch Ausgabe in der Konsole, dass Ihr Code richtig funktioniert. .. **Hausaufgabe 2.2 (1 Punkt)** Volumen eines Ellipsoids: 1) Definieren Sie eine Liste, die 3 strings enthält: ``"a = 4.12"``, ``"b = 13.2"`` und ``"c=4.25"``. ``a``, ``b`` und ``c`` sind die Halbachsen eines Ellipsoids. 2) Extrahieren Sie die Werte für die Halbachsen aus den Strings. Verwenden Sie dazu die erstellte Liste. Achtung: Die Strings können beliebig viele zusätzliche Leerzeichen enthalten! 3) Berechnen Sie das Volumen des Ellipsoids. (Verwenden Sie für :math:`{\pi}` den Wert ``3.1415``.) 4) Erstellen Sie ein Dictionary ``Ellipsoid``, dass die Hauptachsen des Ellipsoids enthält. Dabei soll als Schlüssel der Name als string (z.B. ``a``) und als Wert der Wert als Gleitkommazahl verwendet werden. 5) Testen Sie Ihr Programm mit verschiedenen Anfangslisten (die verschiedene Werte für die Halbachsen und verschieden viele Leerzeichen an beliebiger Stelle enthalten). Definieren Sie dazu Strings mit integer-Zahlen bzw. float-Zahlen verschiedener Längen. Geben Sie in Ihrem Skript an, welche Anfangslisten Sie getestet haben! weitere Beispiele ================= **Aufgabe 3.4** Gegeben sei eine beliebige ``Liste`` z.B. ``5, 7, 2, 0, Orange, 3``. 1) Finden Sie heraus ob sich die Zahl "0" in dieser Liste befindet. 2) Wenn ja, an welcher Stelle befindet sich die Zahl "0"? 3) Löschen Sie das vorletzte Element von dieser Liste und speichern Sie dieses in einer beliebigen Variablen ab. 4) Geben Sie die Länge der Liste aus. 5) Fügen Sie das in 3) entfernte Element ans Ende der Liste an. 6) Multiplizieren Sie die Liste mit ``3`` und überprüfen Sie das Ergebnis mittels ``print``. 7) Multiplizieren Sie jedes Element der Liste mit ``3``. 8) Addieren Sie die Liste und eine beliebige andere Liste, z.B. ``Werte_Liste`` aus Aufgabe 3.1. 9) Erstellen Sie eine neue Liste ``Liste2``, die die ``Liste`` als 0. Element und ``Werte_Liste`` als 1. Element enthält. D.h. eine Liste, die Listen enthält. 10) Kopieren Sie ``Liste2`` explizit. Überprüfen Sie, dass eine Veränderung an der Kopie die ursprüngliche ``Liste2`` nicht verändert. .. hint :: Überprüfen Sie nach jedem Punkt durch Ausgabe in der Konsole, dass Ihr Code richtig funktioniert. **Aufgabe 3.5** Volumen eines Zylinders: 1) Definieren Sie eine Liste, die 2 strings enthält: ``"Hoehe = 3.1524","Radius = 17.54"``, die die Höhe und den Radius eines Zylinders angeben. 2) Extrahieren Sie die Höhe und den Radius aus den Strings. 3) Berechnen Sie das Volumen des Zylinders (definieren Sie dazu ``pi`` als ``3.14159``). 4) Erstellen Sie ein Dictionary ``Zylinder_Dict``, dass Radius, Höhe und Volumen des Zylinders enthält. Dabei soll als Schlüssel der Name als string (z.B. ``Hoehe``) und als Wert der Wert als Gleitkommazahl verwendet werden. 5) Testen Sie Ihr Programm mit verschiedenen Höhen und Radien. Definieren Sie dazu Strings mit integer-Zahlen bzw. float-Zahlen verschiedener Längen. **Aufgabe 3.6** Gegeben ist eine Zeichenkette mit den Einträgen ``1, zwei, 3, 4.12``. Achten Sie bei der Lösung der folgenden Punkte darauf, dass sie auch für einen beliebig langen Anfangsstring funktioniert! 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. .. hint :: Zum Überprüfen ob es sich um Zahlen handelt, könnte die Lösung von Aufgabe 4.1 hilfreich sein. 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. Bestimmen Sie zusätzlich die Gesamtlänge aller Elemente der Liste. 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! **Aufgabe 3.7** Gegeben ist ein Dictionary ``Woerterbuch``, dass als Schlüssel deutsche Wörter und als Werte die entsprechende Übersetzung ins Englische enthält. Z.B. ``'gruen': 'green', 'eines': 'a', 'Gras': 'gras', 'ist': 'is', 'eine': 'a', 'das': 'the', 'ein': 'a'``. 1) Erstellen Sie ein 2. Dictionary ``Woerterbuch_ende``, dass die englischen Wöerter als Schlüssel und die deutschen Wörter als Werte enthält. 2) Ändern Sie Ihre Lösung zu 1), sodass eine Fehlermeldung ausgegeben wird, wenn ein englisches Wort bereits in ``Woerterbuch_ende`` enthalten ist. Für Interessierte: Erweitern Sie Ihre Lösung zu 2). Wenn zu einem englischen Wort (z.B. ``a``) mehrere deutsche Übersetzungen in ``Woerterbuch`` enthalten sind (z.B. ``ein, eine``), wird in ``Woerterbuch_ende`` das englische Wort als Schlüssel und eine Liste aller deutschen Übersetzungen als Wert eingefügt. .. **Hausaufgabe 2.1 (1 Punkt)** Gegeben ist eine Liste ``Zahlen`` mit den Einträgen ``2, 2.5, 3, 'Vier', 9``. Schreiben Sie Code, der die folgenden Punkte löst und lassen Sie sich zu jedem Punkt eine kurze Ausgabe mit erklärendem Text ausgeben. 1) Finden Sie heraus ob sich die Zahl ``2.5`` in dieser Liste befindet. 2) Wenn ja, an welcher Stelle befindet sich die Zahl ``2.5``? Kontrollieren Sie, dass Sie die richtige Stelle gefunden haben, indem Sie die Zahl ``2.5`` aus ``Zahlen`` auslesen. 3) Löschen Sie das vorletzte Element aus ``Zahlen`` und speichern Sie dieses in einer beliebigen Variablen ab. 4) Geben Sie die Länge der Liste aus. 5) Fügen Sie das in 3) entfernte Element ans Ende der Liste an. 6) Multiplizieren Sie die Liste mit ``3`` und überprüfen Sie das Ergebnis mittels ``print``. 7) Multiplizieren Sie jedes Element der Liste mit ``3``. 8) Erstellen Sie eine neue Liste ``Werte`` mit beliebigen Einträgen. Addieren Sie die Listen ``Zahlen`` und ``Werte``. 9) Erstellen Sie eine neue Liste ``doppel_Liste``, die die Liste ``Zahlen`` als 0. Element und die Liste ``Werte`` als 1. Element enthält. D.h. ``doppel_Liste`` ist eine Liste, die Listen enthält. 10) Kopieren Sie ``doppel_Liste`` explizit. 11) Schreiben Sie mindestens 2 Tests um zu überprüfen, dass eine Veränderung an der Kopie die ursprüngliche ``doppel_Liste`` tatsächlich nicht verändert. .. hint :: Überprüfen Sie nach jedem Punkt durch Ausgabe in der Konsole, dass Ihr Code richtig funktioniert. **Hausaufgabe 2.2 (1 Punkt)** Volumen einer Pyramide: 1) Definieren Sie eine Liste, die 2 strings enthält: ``"Seitenlaenge = 7.2"`` und ``"Hoehe = 4.52"``. ``Seitenlaenge`` gibt die Länge der Seitenlänge der quadratischen Grundfläche und ``Hoehe`` die Höhe der Pyramide an. 2) Extrahieren Sie die Seitenlänge und die Höhe aus den Strings. 3) Berechnen Sie das Volumen der Pyramide. 4) Erstellen Sie ein Dictionary ``Pyramide``, dass Seitenlänge, Höhe und Volumen der Pyramide enthält. Dabei soll als Schlüssel der Name als string (z.B. ``Hoehe``) und als Wert der Wert als Gleitkommazahl verwendet werden. 5) Testen Sie Ihr Programm mit verschiedenen Anfangslisten (die verschiedene Werte für die Seitenlänge und die Höhe enthalten). Definieren Sie dazu Strings mit integer-Zahlen bzw. float-Zahlen verschiedener Längen. Geben Sie in Ihrem Skript an, welche Anfangslisten Sie getestet haben!