Die Rohmaterialien

Was werden wir behandeln?
  • Was Daten sind
  • Was Variablen sind
  • Daten-Typen und was man mit ihnen macht
  • Definieren unserer eigenen Datentypen
  • Einleitung

    In jeder kreativen Tätigkeit benötigt man drei Grundzutaten: Werkzeuge, Materialien und Techniken. Zum Beispiel wenn ich male, sind meine Werkzeuge Pinsel, Stifte und Paletten. Die Techniken sind Dinge wie 'Verwaschen', Nass in Nass, Vermischen, Sprühen usw. Schließlich sind die Materialien Farben, Papier und Wasser. Ähnlich ist es, wenn ich programmiere, meine Werkzeuge sind die Programmiersprachen, Betriebssysteme und die Hardware. Die Techniken sind die Programmierkonstrukte, die wir in dem vorhegehenden Teil diskutiert haben, und das Material sind die Daten, die ich manipuliere. In diesem Kapitel betrachten wir die Materialien zum Programmieren.

    Dies ist sicherlich ein langer Teil und von seiner Natur her wirst du ihn etwas trocken finden; die gute Nachricht ist jedoch, dass du nicht alles auf einmal lesen musst. Das Kapitel geht los mit den am meisten verwendeten Grund-Datentypen, dann gehen wir zur Behandlung von Sammlungen von Gegenständen über und betrachten abschließend ein etwas mehr fortgeschrittenes Material. Es ist durchaus möglich, von diesem Kapitel nach den Sammlungen abzuspringen, und sich mit einigen nachfolgenden Kapiteln zu beschäftigen, um dann an den Beginn des harten Bissens für Fortgeschrittene wieder aufzuspringen.

    Daten

    Daten ist einer derjenigen Begriffe, die jedermann verwendet, aber nur wenige richtig verstehen. Mein Wörterbuch definiert sie so:

    "Tatsachen oder Zahlen, aus denen Schlussfolgerungen gezogen werden können; Information"

    Das ist keine große Hilfe, aber es gibt uns dennoch einen Ansatzpunkt. Schauen wir einmal, ob wir die Sache klären können, indem wir nachschauen, wie Daten in der Begriffswelt des Programmierens verwendet werden. Daten sind der “Stoff”, die rohe Information, die unser Prgramm bearbeitet. Ohne Daten kann ein Programm keine sinnvolle Funktion ausführen. Programme manipulieren Daten auf viele Arten, oftmals abhängig vom Daten-Typ. Jeder Datentyp hat auch eine Anzahl von Operationen - Dinge die etwas tun können. Zum Beispiel haben wir gesehen, dass wir Zahlen zusammen addieren können. Die Addition ist eine Operation für den Datentyp Zahl. Daten erscheinen in vielen Typen und wir werden jeden der meisten allgemeinen Typen und die für diese Datentypen zuständigen Operationen betrachten:

    Variablen

    Daten sind im Speicher deines Computers abgespeichert. Wenn du magst, stelle dir eine riesige Wand voll mit Briefkästen vor, wie sie in Posträumen verwendet werden, um die Post zu sortieren. Du kannst einen Brief in irgendeinen Kasten stecken, aber wenn die Briefkästen nicht mit einem Etikett mit Zustellanschrift beschriftet sind, ist dies ziemlich zwecklos. Variablen sind die Etiketten auf den Briefkästen des Speichers deines Computers.

    Zu wissen, wie Daten aussehen, ist zwar eine feine Sache, doch um sie manipulieren zu können, müssen wir fähig sein, auf sie zugreifen zu können und das ist es, wozu Variablen benutzt werden. In der Ausdrucksweise des Programmierens können wir Instanzen von Datentypen erzeugen und diese Variablen zuordnen. Eine Variable ist eine Referenz für einen spezifischen Bereich im Speicher des Computers. Diese Bereich trägt die Daten. In einigen Computersprachen muss eine Variable genau auf den Datentyp passen, auf den sie verweist. Jeder Versuch einer falschen Datentypzuweisung wird einen Fehler verursachen. Einige Programmierer bevorzugen eine solche Art von Sytem, bekannt als statische Typisierung, weil es vor subtilen Bugs schützen kann, die schwierig zu detektieren sind.

    In Python übernimmt eine Variable den Datentyp, der ihr zugewiesen wird. Sie wird diesen Typ beibehalten und du erhältst eine Warnung, wenn du die Daten auf unbekannte Art vermischen willst - so als wenn du versuchst, einen String zu einer Zahl zu addieren. (Erinnerst du dich an die Beispiel-Fehlermeldung? Sie war ein Beispiel für eine solche Art von Fehler.) Wir können den Datentyp ändern, auf die eine Variable zeigt, indem wir die Variable neu zuweisen.

    >>> q = 7         # q ist jetzt eine Zahl
    >>> print q
    7
    >>> q = "Sieben"   # Neuzuweisung von q auf einen String
    >>> print q
    Sieben
    

    Beachte, daß q von Anfang an so gesetzt worden ist, dass es auf die Zahl 7 weist. Es unterstützt diesen Wert solange, bis wir veranlassen, dass es auf den Charakter-String "Sieben" verweist. Das bedeutet, Python-Variablen unterstützen immer den Typ, auf den sie verweisen, aber wir können einfach ändern, auf was sie verweisen, indem wir die Variable neu zuweisen. An diesem Punkt ist der ursprüngliche Wert 'verloren' und Python löscht es aus seinem Gedächtnis (außer eine ander Variable verweist auch darauf); dies ist bekannt als Garbage Collection.

    Garbage Collection kann mit dem Postangestellten verglichen werden, der ab und zu vorbeischaut, und jedes Päckchen entfernt, das in Kästen ohne Beschriftung liegt. Wenn er keinen Besitzer oder eine Adresse auf dem Paket finden kann, dann wirft er es in den Müll. Werfen wir einen Blick auf einige Beispiele von Datentypen und schauen wir einmal, wie das alles zusammenpasst.

    Primitive Datentypen

    Primitive Datentypen werden so genannt, weil sie die grundlegendsten Datentypen sind, die wir beeinflussen können. Komplexere Datentypen sind in Wirklichkeit Kombinationen der primitiven Typen. Diese sind die Bausteine mit denen alle anderen Typen aufgebaut sind; sie sind das Fundament des Computerns. Sie umfassen Buchstaben, Zahlen und etwas, das der Bool'sche Typ genannt wird.

    Zeichen-Strings

    Wir haben diese schon gesehen. Sie sind wörtlich eine Kette oder Abfolge von Schriftzeichen, die auf dem Bildschirm ausgedruckt werden können. (Es gibt sogar auch nicht-ausdruckbare Kontroll-Character).

    In Python können Strings auf verschieden Arten dargestellt werden:

    Mit einfachen Anführungszeichen:

    'Hier ist ein String'

    Mit doppelten Anführungszeichen:

    "Hier ist ein sehr ähnlicher String"

    Mit dreifach doppelten Anführungszeichen:

    """ Hier ist ein sehr langer String, der sich,
        falls wir es wünschen, über mehrere Zeilen erstreckt und Python wird
        die Zeilen vorsehen, die wir eingeben..."""
    

    Ein spezieller Gebrauch der letzten Form ist das Einbauen von Dokumentation in Python-Funktionen, die wir selbst bilden - wir werden das später sehen.

    Du kannst auf die individuellen Zeichen in einem String zugreifen, indem du sie als ein Feld (array) von Zeichen behandelst (mehr zu Arrays siehe unten). Es gibt gewöhnlicherweise auch einige Operatoren zum Manipulieren von Strings, mit denen die Programmiersprache ausgestattet ist - finden eines Unterstrings, verbinden zweier Strings, kopieren von einem zu einem anderen usw.

    String-Operatoren

    Es gibt eine Vielzahl an Operatoren, die auf Strings angewendet werden können. Einige von diesen sind in Python eingebaut, aber viele andere werden von Modulen unterstützt, die du importieren musst (so wie wir es mit sys im Abschnitt über einfache Sequenzen getan haben).

    String-Operatoren

    Operator Beschreibung
    S1 + S2 Verkettung von S1 und S2
    S1 * N N Wiederholungen von S1

    In den folgenden Beispielen können wir diese in Aktion sehen:

    >>> print 'Wieder und ' + 'wieder'    # String-Verkettung
    Wieder und wieder
    >>> print 'Wiederholung ' * 3		        # String-Wiederholung
    Wiederholung Wiederholung Wiederholung
    >>> print 'Wieder ' + ('und wieder ' * 3)  # Kombination von '+' und '*'
    Wieder und wieder und wieder und wieder
    

    Wir können Zeichenstrings auch Variablen zuweisen:

    >>> s1 = 'Wieder '
    >>> s2 = 'und wieder '
    >>> print s1 + (s2 * 3)
    Wiedr und wieder und wieder und wieder
    

    Beachte, dass die letzten beiden Beispiele jeweils das Gleiche ausgeben.

    Stringvariablen in BASIC

    Wenn in BASIC eine Variable eine Stringvariable ist, musst du ihren Namen mit einem $ abschliessen. Hast du das getan, so kannst du ihr nie eine Zahl zuweisen. Ähnlich ist es bei einer Integervariablen ( sie endet mit %), du kannst ihr keinen String zuweisen. BASIC erlaubt sog. 'anonyme Variable', die mit keinem speziellen Zeichen enden. Diese können nur Zahlen speichern, entweder Realzahlen oder Ganzzahlen, aber nur Zahlen. Hier ist ein Beispiel einer Stringvariable in BASIC:

    DIM MeinString$
    
    MeinString$ = "Hallo du da!"
    
    PRINT MeinString$
    

    Tcl - Strings

    Tcl benutzt intern für alles Strings. Vom Blickwinkel des Benutzers ist dies nicht ganz ersichtlich. Um explizit mit einem String zu hantieren, hast du ihn mit doppelten Anführungszeichen zu umgeben. Um einen Wert einer Variablen zuzuweisen, benutzt man in Tcl den set-Befehl und zum Lesen einer Stringvariablen (oder auch einer jeden anderen Variablen in Tcl) setze ein '$' an den Namensbeginn, nämlich so:

    % set Meinstring "Hallo Welt"
    % put $Meinstring
    

    Anmerkung: Sowohl in Tcl als auch in BASIC sind nur doppelte Anführungszeichen erlaubt.

    Integer

    Integer sind Ganzzahlen von einem großen negativen Wert hin zu einem großen positiven Wert. Dies ist ein besonders zu beachtnder Punkt. Normalerweise denken wir bei Zahlen nicht daran, daß sie in ihre Größe eingeschränkt sind, aber im Computer gibt es obere und untere Grenzen. Die Größe der oberen Grenze ist bekannt als MAXINT und ist abhängig von der Anzahl der Bits, die dein Computer verwendet, um eine Zahl darzustellen. Auf den meisten heutigen Rechnern sind es 32 Bits, so dass MAXINT ungefähr um die 2 Billionen liegt.

    Zahlen mit positiven und negativen Werten sind bekannt als Signed Integers. Du kannst auch unsigned Integers (vorzeichenlose Ganzzahlen) erhalten, die nur auf positive Zahlen, einschließlich der Null, beschränkt sind. Das bedeutet, daß es dabei einen größeren Maximalwert von ungefähr 2 * MAXINT oder 4 Billion auf einem 32 Bit-Rechner gibt, so dass wir den ursprünglich für negative Zahlen vorgesehenen Platz für größere positive Zahlen verwenden können.

    Aufgrund der Einschränkung von Integer in ihrer Größe auf MAXINT, führt das Addieren zweier Integer zu einem falschen Ergebnis, wenn die Summe größer als MAXINT ist. In einigen Sytemen/Sprachen wird der falsche Wert geradeso ausgegeben, wie er ist (gewöhnlich mit einer Art geheimen Markierung (Flag), die du überprüfen kannst, wenn du denkst, dass sie gesetzt ist). Normalerweise wird ein Fehlerzustand angezeigt und entweder dein Programm kann den Fehler behandeln oder das Programm wird auf Exit gehen. Python verhält sich nach der letzten Möglichkeit, währen Tcl sich nach der vorhergehenden verhält. BASIC wirft einen Fehler aus, unterstützt aber keine Möglichkeit, diesen abzufangen (zumindest weiß ich nicht wie!).

    Arithmetische Operatoren

    Wir haben die meisten arithmetischen Operatoren, die du brauchen kannst, schon im Teil 'Einfache Sequenzen' aufgeführt, dennoch rekapitulieren wir:

    Arithmetische und Bitweise Operatoren

    Operator mit Beispiel Beschreibung
    M + N Addition von M und N
    M - N Subtraktion N von M
    M * N Multiplikation von M mit N
    M / N Division, entweder Ganzzahl oder Fließkommazahl als Ergebnis, abhängig vom Typ von M und N. Falls M oder N Realzahlen sind (s.u.), ist das Ergebnis real.
    M % N Modulo: findet den Rest von of M dividiert durch N
    M**N Exponentiation: M potenziert mit N

    Wir haben das Letzte vorher noch nicht gesehen, so dass wir uns jetzt ein Beispiel anschauen, bei dem wir einige Integervariablen erzeugen und den Exponential-Operator verwenden:

    >>> i1 = 2     # erzeugt einen Integer und weist ihn i1 zu
    >>> i2 = 4
    >>> i3 = 2**4  # weist das Ergebnis von 2 hoch 4 der Variablen i3 zu
    >>> print i3
    16
    
    

    Integer in BASIC

    BASIC hat einige Sonderregeln bezüglich Integern. Um in BASIC eine Integervariable zu deklarieren, kannst du entweder einen vollständig ungekennzeichneten Namen verwenden oder du kannst BASIC mitteilen, daß es sich um einen Integer handelt, den wir zu speichern wünschen (was etwas effektiver ist). Wir tun dies, indem wir den Namen mit '%' enden lassen:

    FOO = 8   REM FOO kann jede Art von Zahl enthalten
    BAR% = 9  REM BAR kann nur Integer enthalten
    

    Ein Gotcha zum Abschluß mit Integervariablen in BASIC:

    i% = 7
    PRINT 2 * i%
    i% = 4.5
    PRINT 2 * i%
    

    Beachte, dass die Zuweisung von 4.5 auf i% scheinbar funktioniert, aber tatsächlich wird nur der ganzzahlige Teil zugewiesen. Das erinnert an die Art, wie Python die Division von Integern behandelt. Alle Programmiersprachen haben ihre eigenen kleinen Eigenheiten wie diese!

    Tcl - Zahlen

    Wie schon vorher angedeutet, speichert Tcl alles intern als Strings; dennoch macht dies keinen Unterschied für den Anwender, weil Tcl die Werte als Zahlen verdeckt hin und wieder zurück konvertiert, so wie sie waren. Alle anderen Einschränkungen der Zahlengrößen werden auch hier angewandt.

    Der Gebrauch von Zahlen in Tcl ist etwas komplexer, als in den meisten anderen Sprachen, da du jedesmal wenn eine Berechnung durchzuführen ist, dem Interpreter signalisieren mußt, daß eine Berechnung erforderlich ist. Du tust das mit dem expr Kommando:

    % put [expr 6 + 5]
    11
    

    Tcl sieht die eckigen Klammern und wertet diesen Teil zuerst aus, so als wäre dieser allein in die Befehlszeile eingetippt worden. Während dies geschieht, erkennt es den expr - Befehl und es macht die Berechnung. Das Ergebnis kommt dann durch put auf den Bildschirm. Beim Versuch mit put direkt die Summe einzugeben, wird Tcl nur "6 + 5" ausgeben:

    % put 6 + 5
    6 + 5
    

    Realzahlen

    Diese sind gebrochen. Sie können sehr große Zahlen repräsentieren, viel größer als MAXINT, aber mit geringerer Genauigkeit. So kann man sagen, wenn 2 Realzahlen, die identisch sein sollten, dies nicht unbedingt sind, wenn sie vom Computer miteinader verglichen werden. Dies ist deshalb so, weil der Computer die kleinen Anteile nur annähert. So kann 4.0 durch den Computer als 3.9999999.... oder 4.0000001 dargestellt werden. Diese Annäherungen sind für die meisten Anwendungen ausreichend, aber in manchen Fällen werden sie bedeutend. Wenn du einmal ein unsinniges Ergebnis bei dem Gebrauch von Realzahlen erhältst, so behalte dies im Hinterkopf.

    Fließkommazahlen haben die gleichen Operatoren, wie Integer mit der zusätzlichen Möglichkeit, die Zahl auf einen Integerwert zu runden.

    Komplexe oder Imaginär-Zahlen

    Falls du einen wissenschaftlichen oder mathematischen Hintergrund hast, wirst du dann noch etwas über komplexe Zahlen wissen wollen ? Wenn nicht, so hast du noch nichts über komplexe Zahlen gehört! Irgendwie besitzt jede Programmiersprache, einschließlich Python, entweder eine eingebaute Unterstützung für den Komplex-Typ, während andere eine Funktionenbibliothek verwenden, die mit komplexen Zahlen operieren können. Und bevor du noch fragst, dasselbe gilt auch für Matrizen.

    In Python wird eine komplexe Zahl representiert als:

    (real+imaginaryj)
    

    So sieht dann eine einfache Addition mit komplexen Zahlen aus:

    >>> M = (2+4j)
    >>> N = (7+6j)
    >>> print M + N
    (9+10j)
    

    Alle Integer-Operationen lassen sich auch auf komplexe Zahlen anwenden.

    Boole'sche Werte - Wahr und Falsch

    Wie die Überschrift sagt, hat dieser Typ nur 2 Werte - entweder wahr (true) oder falsch (false). Einige Sprachen unterstützen Bool'sche Werte direkt, andere verwenden eine Absprache, bei der numerische Werte (meistens 0) falsch repräsentieren und andere (meist 1 oder -1) wahr repräsentieren.

    Boole'sche Werte sind manchmal bekannt als "Wahrheitswerte", weil sie verwendet werden, um zu überprüfen, ob etwas stimmt oder nicht. Zum Beispiel wenn du ein Programm schreibst, um Sicherheitskopien aller Dateien in einem Verzeichns zu erstellen, so wirst du jedes einzelne File abspeichern und das Betriebssystem nach dem Namen der nächsten Datei abfragen. Wenn keine Dateien mehr vorhanden sind, wird es einen leeren String zurückgeben. Um zu sehen, ob der Name ein leerer String ist, kannst du das Ergebnis als Boole'schen Wert abspeichern (wahr ist leer). Du wirst die Anwendung des Ergebnisses später in diesem Kurs sehen.

    Boole'sche (oder Logische) Operatoren

    Operator mit Beispiel Beschreibung Auswirkung
    A and B UND Wahr, wenn A,B beide wahr sind, andernfalls falsch.
    A or B ODER Wahr wenn entweder einer oder beide von A,B wahr sind. Falsch,wenn beide A und B falsch sind.
    A == B Gleichheit Wahr, wenn A gleich B ist.
    A != B
    or
    A <> B
    Ungleichheit Wahr, wenn A NICHT gleich B ist.
    not B Negation Wahr, wenn B nicht wahr ist.

    Anmerkung: Das Letzte wirkt nur auf einen einzelnen Wert, die anderen vergleichen immer zwei Werte.

    Sammlungen

    Die Computerwissenschaft hat eine komplette Diziplin zum Studium von Sammlungen und ihr unterschiedliches Verhalten geschaffen. Manchmal werden Sammlungen auch als Container beteichnet. In diesem Abschnitt schauen wir uns zuerst alle von Python unterstützten Sammlungen an und werden dann mit einer kurzen Übersicht über Sammlungstypen, die dir bei anderen Programmiersprachen über den Weg laufen, abschließen.

    Python - Sammlungen

    Liste

    Eine Liste ist eine Abfolge (Sequenz) von Bestandteilen. Was diese von einem Feld (Array) unterscheidet, ist, daß sie wachsen kann - du addierst nur ein anderes Teil. Aber eine Indexierung ist nicht üblich, so dass du, um das Teil zu finden, das du brauchst, durch die Liste von Anfang bis Ende durchgehen mußt, um jedes Teil zu testen, ob es dasjenige ist, das du brauchst. Python and Tcl haben beide Listen in die Sprache eingebaut. In BASIC ist es schwieriger und wir müssen trickreich programmieren, um sie zu simulieren. BASIC-Programmierer erschaffen üblicherweise sehr große Arrays an ihrer Stelle. Python erlaubt dir auch eine Liste zu indizieren. Wie wir sehen werden ist dies eine sehr nützliche Eigenschaft.

    List - Operationen

    Python unterstützt viele Operationen für Sammlungen. Nahezu alle werden auf Listen angewendet, und nur ein geringer Teil auf andere Sammlungs-Typen, einschließlich Strings, die ja ein besonderer Typ von Zeichen-Liste ist. Um eine Liste zu erstellen und auf sie zugreifen zu können, benutzen wir in Python eckige Klammern. Du kannst eine leere Liste erzeugen, indem du zwei leere eckige klammern ohne Inhalt verwendest, oder eine gefüllte Liste, indem die Werte innerhalb der eckigen Klammer durch Kommata getrennt werden:

    >>> eineListe = []
    >>> eineandere = [1,2,3]
    >>> print eineandere
    [1, 2, 3]
    

    Wir können auf die einzelnen Elemente zugreifen, indem wir eine Indexnummer innerhalb eckiger Klammern verwenden, wobei das erste Element 0 ist:

    >>> print eineandere[2]
    3
    

    Wir können auf eine ähnliche Art auch den Wert von Elementen verändern:

    >>> eineandere[2] = 7
    >>> print eineandere
    [1, 2, 7]
    

    Du kannst negative Indexzahlen verwenden um Bestandteile vom Ende der Liste aus aufzurufen. Dies wird allgemein durch die Verwendung von -1 , um das letzte Listenteil zu erhalten, durchgeführt:

    >>> print eineandere[-1]
    7
    

    Wir können auch neue Elemente an das Ende der Liste hinzufügen, indem wir den append()-Operator verwenden:

    >>> eineListe.append(42)
    >>> print eineListe
    [42]
    

    Wir können sogar eine Liste innerhalb einer anderen aufbewahren, indem wir unsere zweite Liste an die erste anhängen:

    >>> eineListe.append(eineandere)
    >>> print eineListe
    [42, [1, 2, 7]]
    

    Beachte, dass das Ergebnis eine Liste aus zwei Elementen, aber das zweite Element nochmals selbst eine Liste ist (erkenntlich an den [] drumrum). Dies ist ganz nützlich, da es die Darstellung von Tafeln oder Tabellen mit Listen von Listen ermöglicht. Wir können dann auf das Element 7 unter Verwendung eines Doppelindex zugreifen:

    >>> print eineListe[1][2]
    7
    

    Der erste Index, 1, zieht das zweite Element heraus, das eine Liste ist. Der zweite Index, 2, sondert das dritte Element der Unterliste aus.

    Das Gegenteil des Addierens von Elementen, ist ihr Entfernen und um dies zu tun, benutzen wir den del Befehl:

    >>> del eineListe[1]
    >>> print eineListe
    [42]
    

    Wenn wir zwei Listen miteinander zu einer verbinden möchten, so können wir den gleichen Verkettungsoperator ‘+’ verwenden, den wir uns bei Strings angeschaut haben:

    >>> neueListe = eineListe + eineandere
    >>> print neueListe
    [42, [1, 2, 7], 1, 2, 7]
    

    In gleicher Weise können wir den Wiederholungsoperator anwenden, um eine Liste zu einem Vielfachen des gleichen Wertes zu vermehren:

    >>> nullListe = [0] * 5
    >>> print nullListe
    [0, 0, 0, 0, 0]
    

    Zum Schluss können wir noch die Länge einer Liste begrenzen, indem wir die eingebaute Funktion len() verwenden:

    >>> print len(eineListe)
    2
    >>> print len(nullListe)
    5
    

    Tcl - Listen

    Tcl hat ebenfalls einen eingebauten Listentyp und eine Vielzahl an Kommandos um mit diesen Listen zu operieren. Diese Befehle sind identifizierbar durch das 'l'-Präfix, zum Beispiel linsert, lappend, lindex, usw. Ein Beispiel zur Erzeugung einer einfachen Tcl-Liste und der Zugriff auf ein Bestandteil folgt:

    % set L [list 1 2 3]
    % put [lindex $L 2]
    3
    

    Tuple

    Nicht jede Sprache unterstützt ein Tuple-Konstrukt, aber in denjenigen, die dies tun, ist das extrem nützlich. Ein Tupel ist eine willkürliche Sammlung von Werten, die als eine Einheit behandelt werden können. In vielen Fällen ist ein Tuple wie eine Liste, aber mit dem signifikanten Unterschied, dass Tuples unveränderlich sind; was bedeutet, dass du sie weder verändern noch erweitern kannst, sobald sie einmal erzeugt sind. In Python werden Tuples einfach durch runde Klammern dargestellt, die eine Liste mit durch Kommata getrennten Werten enthält, wie:

    >>> einTuple = (1,3,5)
    >>> print einTuple[1]    # verwende Indexierung wie bei Listen
    3
    >> einTuple[2] = 7       # Fehler, ein Tuple-Element kann nicht geändert werden
    Traceback (innermost last):
      File "", line 1, in ?
      	aTuple[2] = 7
    TypeError: object doesn't support item assignment
    

    Die wichtigsten Dinge, die man sich behalten sollte ist, dass während runde Klammern dazu verwendet werden, um Tuples zu definieren, eckige Klammern zu deren Indizierung verwendet werden, und du kannst, sobald ein Tupel erzeugt ist, dieses nicht mehr verändern. Hingegen werden die meisten Listen-Operationen auch auf Tuple angewandt.

    Dictionary oder Hash

    Ein Dictionary(=Wörterbuch), wie der Name schon andeutet, beinhaltet einen Wert, der mit einem Schlüssel in Verbindung steht, auf dieselbe Art wie im Wörterbuch die Bedeutung eines Wortes mit dem Wort selbst assoziiert ist. Der Wert kann durch 'indexieren' des Dictionary durch den Schlüssel wiedererlangt werden. Anderers als bei einem Wörterbuch, muß der Schlüssel kein Character-String sein (obwohl es oft einer ist), es kann jeder unveränderliche Typ einschließlich Zahlen und Tuple sein. Ähnlich können auch die Werte, die mit den Schlüsseln assoziiert sind, von jeglicher Art Python-Datentyp sein. Dictionaries werden gewöhnlich intern implementiert um eine fortgeschrittene Programmiertechnik zu benutzen, die als Hash-Tabelle bekannt ist. Aus diesem Grunde wird ein Dictionary manchmal auf einen Hash bezogen. Dies hat nichts mit Drogen zu tun!

    Weil der Zugriff auf die Werte des Dictionary über den Schlüssel erfolgt, kann man lediglich Elemente mit einheitlichen Schlüsseln einbringen. Dictionaries sind unheimlich nützliche Strukturen und werden in Python als ein eingebauter Typ unterstützt; hingegen in vielen anderen Sprachen ist erforderlich, daß du ein Modul benötigst oder deine eigenen bauen musst. Wir können Dictionaries auf viele Arten benutzen und wir werden später eine Menge Beispiele sehen, aber jetzt kommt, wie du ein Dictionary in Python erzeugst, es mit einigen Einträgen füllst und die zurückholst:

    >>> dict = {}
    >>> dict['boolean'] = "Ein Wert, der entweder wahr oder falsch ist"
    >>> dict['integer'] = "Eine ganze Zahl"
    >>> print dict['boolean']
    Ein Wert, der entweder wahr oder falsch ist
    

    Beachte, daß wir das Dictionary mit geschwungenen Klammern initialisieren, dann eckige Klammern für die Zuweisung und das Lesen verwenden.

    Durch ihrer inneren Struktur unterstützen Dictionaries nicht viele der Sammlungsoperatoren, wie wir gesehen haben. Keine der Verkettungs-, Wiederholungs- oder Anfüge-Operatoren funktioniert. Um uns beim Zugriff auf Dictionary-Schlüssel zu helfen, gibt es eine Funktion, die wir nutzen können, keys(), die eine Liste aller Schlüssel in einem Dictionary zurückgibt.

    Wenn du dir jetzt ein bisschen abgefüllt vorkommst, so kannst du an diesem Punkt zum nächsten Kapitel hinüber springen. Vergiss nicht zurückzukehren und dies alles zu Ende zu lesen, sobald dir Typen über den Weg laufen, die wir bislang nicht besprochen haben.

    Andere Sammlungs-Typen

    Array oder Vektor

    Das ist eine Auflistung von Gegenständen, die für leichten und schnellen Zugriff indiziert sind. Gewöhnlich hat man hierbei schon vorab festzulegen, wieviele Bestandteile man speichern möchte. Sagen wir, ich habe ein Array, genannt A, dann kann ich den 3ten Gegenstand extrahieren, indem ich A[3] schreibe. Arrays sind fundamental in BASIC, und sie sind tatsächlich der einzige eingebaute Sammlungstyp. In Python werden Arrays durch die Verwendung von Listen simuliert und in Tcl werden Arrays durch Dictionaries implementiert.

    Es folgt ein Beispiel für ein Array in BASIC:

    DIM MeinArray(20) REM erzeuge ein 20-Element-Array
    
    MeinArray(1) = 27
    MeinArray(2) = 50
    FOR i =1 TO 5 
       PRINT MeinArray(i)
    NEXT i
    

    Beachte, dass in BASIC der Index bei 1 beginnt; dies ist ungewöhnlich und in den meisten Sprachen startet der Index bei 0. Es gibt keine anderen Operationen bezüglich Arrays; alles was man tun kann ist, sie erzeugen, Werte zuweisen und Werte lesen.

    Stapel (Stack)

    Denke an ein Stapel Tabletts in einem Selbstbedienungsrestaurant. Ein Angestellter stellt einen Stoß von sauberen Tabletts obenauf, und diese werden einer nach dem anderen durch die Gäste entfernt. Die Tabletts am Ende des Stapels werden ganz zum Schluß ( und zuletzt !) benutzt. Daten-Stapel funktionieren auf die gleiche Weise: du schiebst ein Teil auf den Stack drauf oder schubst einen runter. Der zuletzt runtergeschubste Gegenstand ist immer der zuletzt aufgelegte. Diese Eigenschaft von Stapel wird manchmal "Last In First Out" oder "LIFO" (Letzter rein, Erster raus) genannt. Eine nützliche Eigenart von Stacks ist, dass du die Reihenfolge innerhalb der Liste umkehren kannst, diese auf den Stapel legen und wieder Gegenstände runterschubsen kannst. Das Ergebnis ist die Umkehrung der Ausgangsliste. Stacks sind in Python, Tcl oder BASIC nicht eingebaut. Du musst ein bisschen Programm-Code schreiben, um dieses Verhalten zu implementieren. Listen sind gewöhnlicherweise der beste Ausgangspunkt, da sie wie Stapel auf Wunsch anwachsen können.

    Beutel (Bag)

    Ein Bag ist eine Ansammlung von Gegenständen ohne festgelegte Ordnung und können Duplikate enthalten. Bags haben gewöhnlicherweise Operatoren, die erlauben, Gegenstände zu addieren, zu finden und zu löschen. In Python und Tcl sind Bags genau wie Listen. In BASIC musst du den Bag aus einem großen Array aufbauen.

    Menge (Set)

    Eine Menge hat die Eigenschaft, daß nur jeweils ein Gegenstand gespeichert werden kann. Du kannst gewöhnlicherweise testen, ob ein Gegenstand in einer Menge ist (Mitgliedschaft). Addieren, löschen und zurückholen von Gegenständen und das Verbinden zweier Mengen auf verschiedene Arten korrespondiert mit der Mengentheorie in der Mathematik (z. B. Vereinigung, Schnitt usw.). Keine unserer Beispielsprachen beinhaltet Mengen direkt, aber sie können durch die Verwendung des eingebauten Dictionary-Typs leicht sowohl in Python als auch in Tcl gebildet werden.

    Warteschlange (Queue)

    Eine Warteschlange ist genauso wie ein Stapel, ausgenommen, dass der zuerst eingebrachte Gegenstand in die Schlange auch der zuerst herausgenommene Gegenstand ist. Dies ist bekannt als "First In First Out" - oder FIFO-Verhalten.

    Es gibt noch einen grossen Haufen anderer Sammlungs-Typen, doch das sind die wichtigsten, die du jemals sehen wirst (Wir werden tatsächlich auch nur mit einigen Wenigen von diesen in diesem Lehrgang arbeiten!)

    Dateien (Files)

    Als Computer-Benutzer weißt du alles über Dateien - die einzige Grundlage von nahezu Allem, was wir mit Computern machen. Es wird keine Überraschung sein, zu entdecken, daß die meisten Programmiersprachen einen speziellen File-Datentyp unterstützen. Dennoch sind Dateien und ihre Behandlung so wichtig, dass wir ihre Betrachtung auf später verlegen werden, wenn ihnen ein eigenes Kapitel gewidmet ist.

    Datum und Zeiten

    Datum und Zeiten werden oft eigene Typen in der Programmierung zugeordnet. Manchmal werden sie einfach durch eine große zahl repräsentiert (typischerweise die Zahl an Sekunden ab einem willkürlichen Datum/Zeit). In anderen Fällen ist dieser Datentyp ein komplexer Typ, der im nächsten Abschnitt beschrieben ist. Dies macht es normalerweise leichter, Monat, Tag, Stunde usw. zu entnehmen.

    Komplexer oder benutzerdefinierter Datentyp

    In einigen Fällen sind die oben beschriebenen Datentypen unzureichend, auch wenn sie in Sammlungen kombiniert sind. Was wir manchmal tun wollen, ist, daß wir verschiedene Datenstücke als Gruppe zusammenfassen möchten, um sie als einen einzelnen Gegenstand behandeln zu können. Ein Beispiel hierfür wäre die Beschreibung einer Adresse:
    eine Hausnummer, eine Straße und einen Ort. Schließlich gibt's noch eine Postleitzahl.

    Die meisten Sprachen erlauben uns das Gruppieren solcher Information zusammen in einem Record oder einer Structure.

    In BASIC sieht eine solche Record-Definition wie folgt aus:

    Type Addresse
         Hs_Nummer AS INTEGER
         Strasse AS STRING
         Ort AS STRING
         Postleitzahl AS STRING
    End Type
    

    In Python ist dies ein wenig anders:

    class Addresse:
        def __init__(self, Hs, St, Ort, Plz):
            self.Hs_Nummer = Hs
            self.Strasse = St
            self.Ort = Ort
            self.Postleitzahl = Plz		
    

    Das mag wohl etwas geheimnisvoll ausschauen, aber keine Sorge, ich werde in dem Abschnitt über Objekt-Orientierung erläutern , was das def __init__(...) und die self - Stücke bedeuten. Wenn du versuchst, dies in Python einzutippen, musst du darauf achten, den gezeigten Zeileneinzug genau zu kopieren. Wie du später sehen wirst, ist Python sehr eigen, was die Ebenen des Zeileneinzuges angeht.

    Die Hauptsache, die ich dir hier bewusst machen möchte ist, dass hier unterschiedliche Datenteile in eine einzige Struktur zusammengebracht werden.

    Zugriff auf Komplexe Typen

    Auch komplexe Datentypen können wir einer Variablen zuweisen, aber um auf die einzelnen Felder des Typs zugreifen zu können, müssen wir einen besonderen Zugriffsmechanismus verwenden (der durch die Sprache definiert ist). Üblicherweise ist es ein Punkt.

    Betrachten wir dies im Falle des oben definierten Adressen-Typ, wie wir dies in BASIC tun würden:

    DIM Addr AS Addresse
    Addr.Hs_Nummer = 7
    Addr.Strasse = "Hochstr"
    Addr.Ort = "Einort"
    Addr.Postleitzahl = "12345"
    PRINT Addr.Hs_Nummer," ",Addr.Strasse
    

    Und in Python:

    Addr = Addresse(7,"Hochstr","Einort","12345")
    print Addr.Hs_Nummer, Addr.Strasse
    

    Dies erzeugt eine Instanz von unserem Adressentyp und weist sie der Variablen Addr zu. Dann drucken wir die Hs_Nummer - und Strasse - Felder der neu geschaffenen Instanz unter Verwendung des Punkt-Operators aus.

    Die Art von Tcl

    In Tcl ist die beste Annäherung an den komplexen Datentyp einfach das Abspeichern in eine Liste. Du musst dich an die Abfolge der Felder erinnern können, so dass du sie wieder herausholen kannst. Dies könnte dadurch etwas vereinfacht werden, indem du die Feldnummern bestimmten Variablen zuordnest; nach der Art des obigen Beispiels würde das so aussehen:

    set Hs_num 0
    set Strasse 1
    set Ort 2
    set Plz 3
    set addr [list 7 "Hochstr" "Einort" "12345"]
    puts [format "%s %s" [lindex $addr $Hs_num] [lindex $addr $Strasse]]
    

    Beachte den Gebrauch des Tcl-Format-String und die eingefügten []- Sätze.

    Benutzerdefinierte Operatoren

    Benutzerdefinierte Typen können, zumindest in einigen Sprachen, auch Operationen definiert haben. Dies ist die Grundlage von dem, was als Objektorientiertes Programmieren bekannt ist. Wir widmen später ein ganzes Kapitel diesem Thema, aber grundsätzlich ist ein Objekt eine Ansammlung von Datenelementen und den Operationen, die mit diesen Daten assoziiert sind, zusammengepackt als eine Einheit. Python verwendet Objekte ausgiebig in seiner Modul-Standardbibliothek und erlaubt uns als Programmierer ebenfalls, uns unsere eigenen Objekttypen zu erzeugen.

    Auf Objektoperationen kann genauso zugegriffen werden, wie auf die Datenbestandteile des benutzerdefinierten Typs, nämlich über den Punkt-Operator, aber das sieht eher wie Funktionen aus. Diese Spezialfunktionen werden Methoden genannt. Wir haben dies schon einmal bei der append()-Operation einer Liste gesehen. Zur Erinnerung: wir müssen den Funktions-Aufruf an den Variablennamen anheften, um ihn nutzen zu können:

    >>> listObject = []    # eine leere Liste
    >>> listObject.append(42)	# Aufruf einer Methode des List-Objekts
    >>> print listObject
    [42]
    

    Wenn ein Objekttyp, bekannt als Klasse, in einem Modul unterstützt wird, so müssen wir das Modul importieren (wie wir das früher mit sys getan haben), dann verwenden wir den Modulnamen als Präfix vor dem Objektnamen, um eine Instanz zu erzeugen, die wir in einer Variablen speichern können. Dann können wir die Variable ohne Modulname benutzen.

    Wir werden das durch die Annahme eines fiktiven Moduls nahrung beleuchten, das eine frikadelle-Klasse unterstützt. Wir importieren das Modul, erzeugen eine Instanz von frikadelle und entnehmen ihre Operationen und Daten folgendermaßen:

    >>> import nahrung
    >>> meineFrikadelle = nahrung.frikadelle()  # erzeuge eine Instanz, benutze Modulnamen
    >>> meineFrikadelle.slice()        # verwende eine frikadelle-Operation
    >>> print meineFrikadelle.zutaten  # entnehme frikadelle-Daten
    {Schweinefleisch:40%, Schinken:45%, Fett:15%}
    

    Außer der Erfordernis einer Instanzerzeugung, gibt es hier keine richtigen Unterschiede zwischen dem Gebrauch von Objekten innerhalb von Modulen und Funktionen, die in Modulen zu finden sind. Denke beim Objektnamen einfach an ein Etikett, das die aufeinader bezogenen Funktionen und Variablen zusammen gruppiert.

    Eine andere Betrachtungsweise ist, dass Objekt Dinge der realen Welt repräsentieren, mit denen wir als Programmierer irgenwelche Dinge tun können. Dies ist der Blickpunkt, wo die ursprungliche Idee von Objekten in Programmen herkommt: Das Schreiben von Computersimulationen der Situationen der realen Welt.

    Weder QBASIC noch Tcl unterstützen die Möglichkeiten um Operationen den komplexen Typen hinzu zu fügen. Es gibt aber dennoch eine Zusatzbibliothek für Tcl, die das erlaubt und der modernere Visual-Basic-Dialekt von BASIC macht es möglich.

    Pythonspezifische Operatoren

    Mein Hauptziel in diesem Lehrgang ist, dich programmieren zu lehren und obwohl ich Python in diesem Lehrgang verwende, gibt es keinen Grund, nachdem du dies gelesen hast, nicht auszusteigen und über andere Sprachen nachzulesen und diese an ihrer Stelle zu verwenden. Und genau das ist es, was ich von dir erwarte, denn keine einzige Programmiersprache, auch nicht Python, kann alles machen. Aufgrund dieses Ziels werde ich nicht alle Eigenschaften von Python behandeln, mich aber auf diejenigen konzentrieren, die grundsätzlich auch in anderen Sprachen zu finden sind. Zusammenfassend lässt sich sagen, dass es viele pythonspezifische Eigenschaften gibt, die zwar äußerst leistungsfähig sind, die ich aber nicht beschreiben werde, und das beinhaltet auch Spezialfunktionen. Die meisten Programmiersprachen besitzen Operationen zu ihrer Unterstützung, die andere wiederum nicht haben. Oftmals sind es diese 'einzigartigen' Operatoren die neue Programmiersprachen ans Tageslicht bringen, und die sicherlich auch ein wichtiger Faktor sind, damit eine Sprache populär wird.

    So unterstützt Python zum Beispiel solche relativ unüblichen Operationen wie das Slicing von Listen ( frikadelle[X:Y] ) und Mehrfachzuweisungen ( X, Y = 12, 34 ). Es hat auch die Möglichkeit, eine Operation mit jedem Mitglied einer Sammlung unter Verwendung seiner map()-Funktion durchzuführen. Es gibt vieles mehr, so dass oft gesagt wird "Python wird einschliesslich Batterien geliefert". Für die Details, wie diese pythonspezifischen Operationen arbeiten, musst du die Python Dokumentation konsultieren.

    Abschließend ist es wichtig zu betonen, dass obwohl ich sagte, diese Dinge seien pythonspezifisch, es nicht heißt, diese seien nicht in anderen Sprachen zu finden; aber dennoch werden sie nicht alle in jeder Sprache zu finden sein. Die Operatoren, die wir im Haupttext behandeln, sind grundsätzlich in irgendeiner Form in allen modernen Programmiersprachen zugänglich.

    Dies beschließt unsere Betrachtung des Rohmaterials des Programmierens; so laß uns übergehen zu einem erfrischenderen Thema über die Technik und sehen, wie man dieses Material zum Funktionieren bringt.

    Zur Erinnerung
    • Daten erscheinen in vielen Typen und die Operationen, die du erfolgreich ausführen kannst, hängen von den verwendeten Datentypen ab.
    • Einfache Datentypen umfassen Character-Strings, Zahlen, Boole'sche oder "Wahrheits-Werte.
    • Komplexe Datentypen beinhalten Sammlungen, Dateien, Datumsangaben und benutzerdefinierte Datentypen.
    • Es gibt viele Operatoren in jeder Programmiersprache and ein Teil des Erlernens einer neuen Sprache ist das vertraut werden mit beiden, ihren Datentypen und den zugehörigen Operatoren.
    • Der selbe Operator (z.B. Addition) kann für unterschiedliche Typen verwendet werden, aber das Ergebnis muß nicht identisch sein, oder auch nur irgendwie vergleichbar!

    zurück  weiter  Inhalt


    Bei Fragen oder Anmerkungen sende eine Nachricht in Englisch an alan.gauld@yahoo.co.uk oder in Deutsch an bup.schaefer@freenet.de