Python

Willemers Informatik-Ecke

Diese Seite basiert auf Inhalten aus dem Buch
Arnold Willemer: UNIX-Das umfassende Handbuch
Verlagsrechte bei Galileo Press

Weitere Python-Themen

Die Sprache Python ist eine Skriptsprache, die durch ihre Nähe zur Syntax der Sprache C sehr viel leichter zu lesen ist, als die Sprache Perl. Bei aller Leistungsfähigkeit wird Perl und den Shellskript-Sprachen gern vorgeworfen, es seien »Write-Once"=Sprachen«. Der Code könne wohl einmal geschrieben werden, es wäre aber völlig aussichtslos, ein einmal geschriebenes Skript zu erweitern oder zu korrigieren.

Interpreter und Skript

Der Python-Interpreter heißt python und befindet sich im Verzeichnis /usr/bin. Das ist deswegen so wichtig, weil in einem Python-Skript angegeben wird, wie der Interpreter heißt. Dazu schreiben Sie in die erste Zeile eines Python-Skripts:

#!/usr/bin/python

Anschließend wird die Datei mit Hilfe des Befehls chmod ausführbar gemacht. Danach kann das Skript direkt von der Kommandozeile aus aufgerufen werden.

Ein- und Ausgabe und Variablen

print

Der Befehl print gibt Variablen und Konstanten auf dem Bildschirm aus. Es können mehrere Argumente angegeben werden, die dann durch Komma getrennt werden müssen. Im ersten Programm wird einfach nur eine kurze Meldung auf den Schirm geworfen.

Ein erstes Python-Skript

#!/usr/bin/python
print "Hallo Mensch!"

Das Programm gibt auf dem Bildschirm einfach die Meldung »Hallo Mensch!« aus.

input

Die Funktion input() stoppt das Programm und wartet auf die Eingabe des Benutzers. Es möchte aber unbedingt einen Zahlenwert als Eingabe haben. Alles andere beendet das Programm.

Wenn Sie aber lieber einen Namen oder eine sonstige Zeichenkette eingeben lassen wollen, sollten Sie Sie die Funktion raw_input() verwenden. Sie nimmt alles, was kommt.

Kleines Frage- und Antwortspiel

#!/usr/bin/python
print "Hallo! Wie heißen Sie?"
antwort = raw_input()
print "Oh, Guten Tag,",antwort

Variablennamen bestehen aus Buchstaben, Ziffern und dem Unterstrich und dürfen nicht mit einer Ziffer beginnen. Die Groß- und Kleinschreibung ist signifikant. Hallo und hallo sind also zwei unterschiedliche Variablen.

Ein Fehler ist ein Ausnahmefall

Fehler führen bei Python normalerweise zu einem Programmabbruch. Das wirkt erst einmal ausgesprochen intolerant. Aber es ist relativ einfach, Fehler abzufangen. Dazu wird dort, wo ein Fehler zu erwarten ist, ein Block mit dem Befehl try (engl. versuchen) aufgebaut. Alles, was in dem try-Block steht, darf zu einem Fehler führen. Für den Fall, dass wirklich ein Fehler passiert, baut der Programmierer einen Block mit except. Dieser Block wird nur im Fehlerfall ausgeführt und sollte dafür sorgen, dass das Programm ordentlich weitergeführt werden kann.

Das Beispiel zeigt eine Eingabe mit input(). Diese Funktion erlaubt nur die Eingabe von Zahlen. Wenn aber jemand dennoch einen Buchstaben oder einen Namen eingibt, wird der except-Block aufgerufen.

Ausnahmebehandlung

try:
    zahl = input()
except:
    print "Falsche Eingabe"

Den Funktionen input() und raw_input() können in ihren Klammern Zeichenketten übergeben werden, die dann direkt vor der Eingabe auf dem Bildschirm erscheinen:

zahl = input("Bitte eine Zahl eingeben: ")

Umgang mit Zahlen

Computer konnten von Anfang an schon prima rechnen, und das ist auch bei Python nicht anders.

Rechnen

Python verwendet die seit Fortran übliche Schreibweise für mathematische Ausdrücke. Links steht meist die Variable, die das Ergebnis aufnimmt. Nach dem Gleichheitszeichen folgen die Werte und Variablen. Zwischen ihnen stehen dann die klassischen Rechenoperatoren.

Zuweisung

Variable = Ausdruck

Die Tabelle zeigt die unter Python gängigen Operatoren.

Binäre numerische Operatoren

OperatorWirkung
+ Addition
- Subtraktion
* Multiplikation
/ Division
% Modulo (Rest einer ganzzahligen Division)
** Potenzierung

Statt den Wert einer Variablen zuzuordnen, können sie auch gleich ausgegeben werden, wie im Beispielprogramm.

Rechnen für Anfänger

#!/usr/bin/python
print 17 + 4     # 21
print 3 -6       # -3
print 3.5 * 7    # 24.5
print 24 / 5     # 4
print 23 % 7     # 2
print 2 ** 4     # 16

In den Kommentaren hinter den Berechnungen finden Sie die Ergebnisse. Mit Hilfe eines Taschenrechners werden Sie die Ergebnisse sicher leicht nachvollziehen können. Es könnte sein, dass Sie bei der Division stutzen. Aber denken Sie daran: Der Computer hat immer Recht. In diesem Fall stehen dort zwei ganzzahlige Werte. Also geht Python davon aus, dass auch ein ganzzahliges Ergebnis gewünscht ist. Wenn Sie 24.0 statt 24 verwenden, kommt auch prompt das Ergebnis 4.8 heraus.

Punkt ist Komma

Bei der Gelegenheit sollte erwähnt werden, dass die Zahlenschreibweise stark durch den angloamerikanischen Raum bestimmt ist. Und dort wird der Punkt als Dezimalkomma verwendet. Es steht zu fürchten, dass Sie sich damit arrangieren müssen.

Natürlich gilt auch im angloamerikanischen Raum, dass die Punkt- vor der Strichrechnung kommt. Und genauso gibt es Klammern bei Python, mit denen man diese Regel umgehen kann, wenn es erforderlich ist.

Geklammert

#!/usr/bin/python
print 17 + 4 * 2       # 25
print (17 + 4) * 2     # 42

Faulenzer

Häufig kommt es vor, dass eine Variable um eins erhöht oder verdoppelt wird. Dort steht dann a=a+1 oder b=b*2. Stattdessen können Sie kürzer a+=1 oder b*=2 schreiben.

Formatierte Ausgabe von Zahlen

Für die Ausgabe von Tabellen ist es wichtig, Zahlen formatiert ausgeben zu können. Für diesen Zweck wird eine Zeichenkette erstellt, die beschreibt, wie formatiert werden soll. Es folgt ein Prozentzeichen und dann die Variablen in Klammern, die ausgegeben werden sollen.

Die Formatzeichenkette enthält an der Stelle ein Prozentzeichen, an der eine Variable dargestellt werden soll. Es folgt ein Zeichen, das die Darstellungsart angibt. Dabei steht beispielsweise f für Fließkommazahlen mit Dezimalpunkt und i für ganzzahlige Darstellung.

Darstellungsart

KürzelBedeutung
f Fließkommazahl in Dezimalpunktdarstellung
e Fließkommazahl in Exponentialdarstellung
i ganzzahliger Wert in dezimaler Darstellung
o ganzzahliger Wert in oktaler Darstellung
x ganzzahliger Wert in hexadezimaler Darstellung mit kleinen Buchstaben
X ganzzahliger Wert in hexadezimaler Darstellung mit großen Buchstaben
i ganzzahliger Wert in dezimaler Darstellung
s Zeichenkette

Zwischen dem Prozentzeichen und dem Buchstaben für den Typ steht die Zahl der Stellen, die der Gesamtausdruck erhält. Bei Fließkommadarstellung in Dezimalpunktdarstellung sind das zwei Zahlen, getrennt durch einen Punkt. Die erste gibt die Gesamtbreite und die zweite Zahl die Anzahl der Nachkommastellen an. Ein Beispiel veranschaulicht dies:

x = 5.149
y = 5
for i in range(1,10):
    print "Fliesskomma: %7.2f und nun Hex: %6X" % (x+i,y+i)

Die Ausgabe dieser Reihe ergibt folgende kleine Tabelle:

Fliesskomma:    6.15 und nun Hex:      6
Fliesskomma:    7.15 und nun Hex:      7
Fliesskomma:    8.15 und nun Hex:      8
Fliesskomma:    9.15 und nun Hex:      9
Fliesskomma:   10.15 und nun Hex:      A
Fliesskomma:   11.15 und nun Hex:      B
Fliesskomma:   12.15 und nun Hex:      C
Fliesskomma:   13.15 und nun Hex:      D
Fliesskomma:   14.15 und nun Hex:      E

Umgang mit Zeichenketten

Die Welt besteht nicht aus lauter Zahlen. Tatsächlich begegnen uns Texte sehr viel häufiger, und eine Skriptsprache dient auch eher der Auswertung von Protokolldateien als der Lösung numerischer Probleme.

Wie in allen gängigen Programmiersprachen wird auch in Python ein Text in Anführungszeichen gesetzt, wenn er im Listing erscheint. Für die Speicherung scheint Python auf den ersten Blick keine Unterschiede zwischen Zahlen und Zeichenketten zu machen.

Aneinanderhängen

Das Pluszeichen wird bei Zeichenketten dazu verwendet, Texte aneinanderzuhängen. Einen Namen können Sie in der üblichen Reihenfolge aus Vor- und Nachnamen ausgeben. Dazwischen steht ein Leerzeichen.

Das folgende kleine Programm spielt mit dem Aneinanderhängen von Texten.

Namensausgabe

#!/usr/bin/python
vor = "James"
nach = "Bond"
print vor + " " + nach
print nach + ", " + vor
print nach + ", " + vor + " " + nach

Länge eines Strings

Die Funktion len() stellt fest, wie viele Zeichen die Zeichenkette enthält, die als Parameter übergeben wird.

Das Auslesen einzelner Zeichen erfolgt durch rechteckige Klammern. Die Zahl gibt an, der wievielte Buchstabe gemeint ist. Sie können also nach[2] mit Hilfe des Befehls print ausgeben. Unter Python ist es aber nicht möglich, ein Zeichen in einer Zeichenkette durch direkte Zuweisung zu ersetzen. nach[2]='r' wird also aus Mr. Bond keinen Mr. Bord machen.

In Python kann mit Hilfe der rechteckigen Klammern auch auf eine Zeichenfolge zugegriffen werden. Dazu wird zunächst die Position des ersten Buchstabens, dann ein Doppelpunkt und schließlich die Position des letzten gewünschten Buchstabens angegeben.

#!/usr/bin/python
name = "Poseidon"
print name[2:6]

Der Index beginnt bei 0

Die Ausgabe ergibt das Wort »seid«. Falls Sie eher mit »osei« gerechnet hatten, haben Sie vermutlich den ersten Buchstaben mit der Position 1 belegt. Computer sind da etwas komisch. Die meisten Programmiersprachen beginnen beim Zählen mit der 0.

Die Möglichkeit, einzelne Zeichen im String über die rechteckigen Klammern zu verändern, funktioniert in Python nicht. Python wird eine Fehlermeldung ausgeben und den Skript radikal beenden.

String-Bibliothek

Import

Für Zeichenketten gibt es eine eigene Bibliothek. Um sie zu benutzen, muss vorher der Befehl zum Import der Funktionen der Bibliothek gegeben werden.

from string import *

Nun stehen Ihnen einige hilfreiche Funktionen zur Verfügung. Die wichtigsten sind hier im Überblick aufgeführt.

Zählen

Die Funktion count() zählt das Auftreten des Suchbegriffs innerhalb der Originalzeichenkette und liefert es in der Variablen Anzahl ab.

Anzahl = count(Originalzeichenkette, Suchbegriff)

Zeichenkette suchen

Mit der Funktion find() kann ein Suchbegriff in der Originalzeichenkette gesucht werden. Die Position wird zurückgeliefert.

Position = find(Originalzeichenkette, Suchbegriff)

Positionsfindung

Ist die Position negativ, wurde der Suchbegriff in der Zeichenkette überhaupt nicht gefunden. Andernfalls wäre es vielleicht interessant, auch weitere Vorkommen des Suchbegriffs zu finden. Kein Problem: Die gefundene Position wird um 1 erhöht und dann als dritter Parameter der Funktion find() übergeben.

NaechstePosition = find(Originalzeichenkette, Suchbegriff, Position+1)

Rückwärts suchen

Die Funktion rfind() bietet die Möglichkeit die Originalzeichenkette von hinten nach vorn nach dem Suchbegriff zu durchforsten.

Rueckwaerts = rfind(Originalzeichenkette, Suchbegriff)

Ersatzmöglichkeit

Mit der Funktion replace() ist es dann auch möglich, in der Zeichenkette AlterString nach »Saulus« zu suchen und diesen durch »Paulus« zu ersetzen. Dabei verändert sich AlterString allerdings nicht, sondern Sie erhalten als Rückgabewert einen NeuenString.

NeuenString = replace(AlterString, "Saulus", "Paulus")

Kleinholz

Die Funktion split() zerlegt eine Zeichenkette an allen Stellen, an denen ein Leerzeichen vorliegt. Das Ergebnis ist keine Zeichenkette, sondern eine Sequenz von Zeichenketten. Darin ist jedes Wort der Originalzeichenkette separat über einen Index in einer eckigen Klammer ansprechbar.

StringArray = split(Originalzeichenkette)

Konvertierung

int long float

Zahlen können direkt zum Rechnen verwendet werden. Bei der Ein- und Ausgabe verwendet man, insbesondere bei grafischen Oberflächen, in erster Linie Zeichenketten. Auch Zahlen, die in Protokolldateien vorliegen, sind erst einmal eine Folge von Buchstaben und müssen in verrechenbare Zahlen umgewandelt werden. Diese Konvertierungen kommen in der Praxis also recht häufig vor.

GanzeZahl = int(Zeichenfolge)
GanzeZahl = long(Zeichenfolge)
FliesskommaZahl = float(Zeichenfolge)

str

Auf der anderen Seite wird eine Zahl mit der Funktion str() in eine Zeichenkette umgewandelt.

Zeichenkette = str(Zahl)

Verzweigung

Abfragen werden wie bei den meisten Programmiersprachen mit dem Schlüsselwort if eingeleitet. Danach kommt direkt die Bedingung, die durch einen Doppelpunkt abgeschlossen wird.

Alle Befehle, die nur unter der Bedingung ausgeführt werden, werden eingerückt. Gilt die Bedingung nicht, wird Python nach der nächsten Zeile suchen, die mit der Abfrage gleich eingerückt ist.

Struktur einer if-Anweisung

if <Bedingung>:
        <Befehle>
[elif <Bedingung>:
        <Befehle> ]*
[else:
        <Befehle> ]

Es können daraufhin ein oder mehrere elif-Anweisungen mit je einer Bedingung und einem Befehlsblock folgen. Die Anweisungen des Befehlsblocks wird ausgeführt, wenn die Bedingung des elif zutrifft und alle vorigen Bedingungen nicht eingetroffen sind.

Schließlich kann optional am Ende eine else-Anweisung folgen. Sie wird ausgeführt, wenn keine der Bedingungen zutraf.

Die Befehle elif und else werden später im Abschnitt noch genauer ausgeführt. Es ist auch wichtig, dass elif und else auf gleicher Höhe mit if stehen. Hier erst einmal ein einfaches Beispiel für eine if-Anweisung.

Einfache Abfrage

if x>10:
   printf "x ist höher als 10!"
print "x ist ", x

In jedem Fall wird »x ist ...« ausgegeben. Sollte aber der Inhalt von x größer als 10 sein, wird vorher noch »x ist höher als 10!« ausgegeben.

else

Python kennt auch else, das den jeweils anderen Fall der Bedingung behandelt.

Nicht selten gibt es Folgen von Bedingungen. Für diese Fälle bietet Python den Befehl elif, der eine Verschmelzung von else und if darstellt. Auf diese Weise wird verhindert, dass die Verschachtelungen die Einrückungen zu weit nach rechts treiben.

Diverse Abfragen

if x>2:
   printf "Diese Zahl ist größer als 2"
elif x==2:
   printf "Zahl ist gleich 2"
else:
   printf "Das ist kleiner als 2"

Bedingungen

Die logischen Operatoren gleichen denen in C und den davon abgeleiteten Sprachen wie Java, C++ oder C#. Auch in Perl werden diese Operatoren verwendet.

Logische Operatoren

Operator} Bedeutung
> größer
< kleiner
<= kleiner oder gleich
>= größer oder gleich
== gleich
!= ungleich

Diese Operatoren werden als binär bezeichnet, weil sie immer zwei Werte miteinander vergleichen. Es wird also bei Zahl<2 ausgewertet, ob der Inhalt der Variablen Zahl kleiner als 2 ist. Das Ergebnis ist ein boolescher Wert, der wahr oder falsch sein kann.

Boolesche Verknüpfung: and, or

Auch boolesche Werte können verknüpft werden. So ließe sich prüfen, ob die Zahl kleiner als 2 ist und größer als 0 ist. Hier müssen beide Bedingungen zutreffen. Die Teilabfragen Zahl<2 und Zahl>0 müssen mit UND verknüpft werden. In der Sprache Python wird hier and verwendet. Will man prüfen, ob ein Wert außerhalb des Intervalls von 0 und 2 liegt, dann ist er kleiner als 0 oder größer als 2. Er kann ja nicht beides gleichzeitig sein. Hier wird ODER verwendet. In der Sprache Python als or bezeichnet.

Als unärer logischer Operator steht not zur Verfügung. Damit lässt sich das Ergebnis negieren.

Bei Zeichenketten gibt es den Operator in, über den festgestellt werden kann, ob eine Zeichenfolge in einer Zeichenkette enthalten ist.

if "murks" in Name:
    print "nomen est omen"
else:
    print "Greenhorn!"

Boolesche Variablen

Die Ergebnisse von Bedingungen können auch in Variablen gespeichert werden. Dazu werden sie einfach einer Variablen zugewiesen. Solche Variablen können auch direkt mit den Schlüsselwörtern True oder False vorbelegt werden.

Schleifen

Schleifen sind Konstrukte, die dazu dienen, Abläufe zu wiederholen. Ein Vorgang wird für mehrere Fälle durchlaufen oder wiederholt, bis ein bestimmtes Ergebnis vorliegt.

for

Die for-Schleife arbeitet wie im Shellskript, in dem der Variablen nacheinander die Elemente einer Liste zugewiesen werden.

Die for-Schleife

for <Variable in Liste:
        <Kommandos

Es folgt ein einfaches Beispiel für solch eine Schleife. Aus einer Liste von Zahlen wird die Variable i gefüllt. Innerhalb der Schleife wird sie ausgegeben und dann das Quadrat der Zahl.

for-Schleife

for i in 3, 4.5, 8:
    print "Zahl: ", i
    print " Quadrat: ", i*i

In anderen Sprachen wird for für Zählschleifen verwendet. Dies lässt sich in Python über die Funktion range() erreichen. Die Funktion range() liefert eine Liste der Zahlen, die durch die drei Parameter bestimmt werden.

for-Schleife

for i in range(1,11,1):
    print "Zahl: ", i
    print " Quadrat: ", i*i

Die Schleife berechnet die Quadratzahlen von 1 bis einschließlich 10. Die Funktion range() hat also drei Parameter. Der erste ist der Startwert, mit dem die Schleife beginnt. Der zweite Parameter ist der erste Wert, der nicht mehr von der Schleife bearbeitet wird. Und der dritte Parameter gibt die Schrittweite der Schleife an.

while

Eine etwas andere Schleife stellt die while-Schleife dar. Sie wird so lange durchlaufen, wie die Bedingung hinter dem Schlüsselwort while zutrifft.

Die while-Schleife

while <Bedingung>:
        <Befehle>

Hierin liegt allerdings auch ihr Risiko. Es geschieht oft, dass ein Programmierer übersieht, dass die Bedingung nie zutreffen kann. So kommt es zu der gefürchteten Endlosschleife. Der Computer ist beschäftigt, bis der Strom ausfällt. Hier folgt ein Beispiel für eine hoffentlich korrekte Schleife.

while-Schleife

i = 0
while i<50:
    i = i * i + 1

print "Ergebnis", i

Das Ergebnis ist natürlich 677. Falls Sie es auf die Schnelle nicht im Kopf nachrechnen konnten, lassen Sie einfach das Programm laufen.

Die while-Schleife eignet sich auch dazu, Eingaben so lange zu wiederholen, bis die Eingabe den Erwartungen entspricht.

Eingabeprüfung

Die folgende Schleife wird erst verlassen, wenn ein gültiger Zahlenwert eingegeben wird. Eine Zeicheneingabe führt bei input() zu einem Ausnahmefehler, der hier mit try und except behandelt wird. Erst wenn es gelungen ist, eine Zahl einzugeben, wird die Schleife verlassen.

while-Schleife

#!/usr/bin/python

NoInput = True while NoInput: try: zahl = input() NoInput = False except: print "Falsche Eingabe: Bitte Zahl eingeben!"

print zahl

Die Variable NoInput wird zu Anfang mit True vorbesetzt. Sie wird nach Aufruf der Funktion input() auf False gesetzt. Sobald die Eingabe erfolgreich verlief, wird die Schleife verlassen, weil die Bedingung hinter while nicht mehr zutrifft. Wenn allerdings keine gültige Zahl eingegeben wird, wird input() sofort eine Ausnahmebehandlung auslösen und der nächste Befehl wird nicht mehr erreicht. Die Ausnahmebehandlung macht nicht viel. Sie meldet nur eine falsche Eingabe.

Funktionen

Befehlszusammenfassung

Am Beispiel des Befehls input() wurde bereits eine Funktion beschrieben. Die Funktion wartet auf Tasteneingaben, stellt die eingetippten Buchstaben zu einer Zahl zusammen und löst eine Ausname aus, wenn keine gültige Zahl vorliegt. Diese Befehle werden jedes Mal durchlaufen, wenn die Funktion aufgerufen wird. Anschließend springt sie dahin zurück, von wo sie aufgerufen wurde.

Vorteile eigener Funktionen

Als Programmierer können Sie auch Funktionen schreiben, die einmal festlegen, welche Befehle abgearbeitet werden und die dann von mehreren Stellen des Programms aufgerufen werden können. Dadurch ersparen Sie sich doppelte Tipparbeit. Darüber hinaus wird ein Fehler, den Sie in einer Funktion beseitigen, mehreren Stellen des Programms zugute kommen. Ein ganz wichtiger Aspekt ist, dass Sie Ihr Hauptprogramm von Details entlasten. Es wird leichter lesbar, damit übersichtlicher, verständlicher und leichter zu korrigieren, wenn Sie mal einen Fehler im Programm haben.

Sie legen zu Anfang Ihres Programms mit dem Befehl def fest, dass Sie eine Funktion definieren. Dieser Code wird dann bei der Ausführung zunächst übersprungen und erst aktiv, wenn Sie ihn aufrufen. Es folgt der Name der Funktion, über den Sie diese aufrufen möchten. Dann folgt eine Klammer, in der Parameter stehen können. Das sind Werte, die der Aufrufer an die Funktion übergibt.

Funktionsdefinition

def <Funktionsname(Parameter):
    <Befehle
    return <Ausdruck

Die Funktion stern besteht aus einer Schleife, die nur einen Stern nach dem anderen ausgibt, je nachdem, wie groß die Zahl ist, die per Parameter übergeben wird.

Funktion definieren

def stern(anzahl):
   for i in range(0,anzahl,1):
       print "*",
   print
...
stern(12) # zeigt 12 Sterne an

Funktionen können Werte zurückgeben. Dazu gibt es das Schlüsselwort return, das auch gleich die Funktion verlässt. Der Rückgabewert wird in den meisten Fällen beim Aufruf einer Variablen zugewiesen.

Funktion Quadrat mit Parametern und Rückgabewert

def quadrat(wert):
   return wert*wert
...
Quadratzahl = quadrat(15)

Die Funktion quadrat() gibt das Quadrat des Parameters zurück. Dieser Wert kann beim Aufruf einer Variablen zugewiesen werden.

Erweiterte Datentypen

Programme bilden Abläufe der Realität nach. Sobald die Programme eine Komplexität haben, die auch Objekte der Realität nachbilden, reichen Zahlen und Texte allein nicht mehr aus. Reale Objekte haben eine Vielzahl von Daten die zusammengehören.

Sequenzen

Bei einer Sequenz handelt es sich um eine Folge gleicher Typen. Eine Form der Sequenzen wurden schon erwähnt. Zeichenketten sind Sequenzen. Sie müssen in Python nicht speziell deklariert werden. Eine Variable wird durch eine entsprechende Zuweisung zur Sequenz. Wird einer Variablen eine Zeichenkette zugewiesen, ist es automatisch eine Sequenz und Sie können die einzelnen Buchstaben über die rechteckige Klammer auslesen.

Sequenzen werden eigentlich nur für Zeichenketten verwendet. Die Unmöglichkeit, einzelne Elemente einer Sequenz zu verändern, ist für die meisten anderen Fälle hinderlich.

Listen

Eine Liste kann ebenfalls mehrere Datenobjekte kombinieren. Allerdings müssen die Datenobjekte nicht vom gleichen Typ sein. Ein weiterer Unterschied zur Sequenz besteht darin, dass ein Element einer Liste direkt verändert werden kann.

Konstante

Eine Variable wird zur Liste, indem man sie im Programm vorbelegt. Dazu werden die Elemente der Liste durch Kommata getrennt und die Liste von rechteckigen Klammern eingerahmt.

Lottozahlen = [ 5, 12, 17, 22, 31, 43 ]
Metropolen = [ "Hamburg", "Norgaardholz", "London" ]

Auch die Elemente einer Liste können über die rechteckigen Klammern angesprochen werden. Im Unterschied zur Sequenz können Elemente der Liste verändert werden.

Lottozahlen[2]=16

Das folgende Beispiel arbeitet mit einer doppelt verschachtelten Liste. Die innere Liste besteht aus einem Ortsnamen, der Einwohnerzahl und einem Kennzeichen. Aus diesen Elementen wird eine Liste gebildet. Eigentlich ist es sogar eine Sequenz.

Das Datenelement wird einfach über rechteckige Klammern zusammengefasst. Die Ausgabeschleife zeigt, dass mit einer einfachen rechteckigen Klammer auf ein Listenelement zugegriffen wird.

#!/usr/bin/python
MeineListe = [ ["Norgaardholz", 249, "FL"],
               ["Bad Homburg", 61253, "HG"],
               ["Husum", 24327, "NF"]
             ]
for i in range(0,3,1):
    print MeineListe[i]
    for j in range(0,3):
        print MeineListe[i][j]

Auch Elemente einer verschachtelten Liste können nachträglich geändert werden. Der folgende Befehl ändert das Kfz-Kennzeichen von Norgaardholz in SL.

MeineListe[0][2] = "SL"

Elemente der Liste können gelöscht werden. Der Befehl dazu lautet del.

del MeineListe[1]

Sie können mit dem Befehl insert an beliebiger Stelle ein Element in die Liste einfügen. Mit dem Befehl append wird das neue Element immer am Ende angehängt.

MeineListe.insert(1, ["Berlin", 3000000, "B"])
MeineListe.append(["Berlin", 3000000, "B"])

Mit Hilfe der Funktion sort() kann eine Liste sortiert werden.

MeineListe.sort()

Im Falle der verschachtelten Liste des Beispiels wird von der inneren Liste das erste Element als Sortierkriterium verwendet.

Es können auch Elemente aus der Liste entfernt werden.

MeineListe.remove(["Husum", 23322, "NF"])

Das Element muss exakt bezeichnet werden. Dann wird genau dieses Element entfernt. Sobald nur Teile des Elements benannt werden, führt remove() zu einer Ausnahme, die mit try aufgefangen werden muss.

Tupel

Ein Tupel entspricht einer Liste, allerdings sind deren Elemente nach der Definition nicht mehr änderbar.

Tupelkonstanten unterscheiden sich von den Listenkonstanten dadurch, dass runde statt rechteckige Klammern verwendet werden.

Lottozahlen = ( 5, 12, 17, 22, 31, 43 )
Metropolen = ( "Hamburg", "Norgaardholz", "London" )

Dictionaries

»Dictionary« heißt auf Deutsch «Wörterbuch«. So funktioniert dieser Datentyp auch. Es gibt einen Suchbegriff und eine Erläuterung. Der Suchbegriff bezeichnet der Informatiker als Schlüssel. Die Erläuterung als den zugehörigen Datenbereich. Über diesen Schlüssel kann schnell ein Eintrag gefunden werden.

Dictionary

kfz = {"sl":"Schleswig", "fl":"Flensburg","hh":"Hamburg"}
kfz["hg"] = "Bad Homburg"
kfz["hg"] = "Hochtaunuskreis"
key = "hg"
print "Schluessel = ", key, " Wert = ", kfz[key]

Definition

In der ersten Zeile wird ein Dictionary namens kfz definiert. Man erkennt das Dictionary an den geschweiften Klammern und dem Doppelpunkt zwischen Schlüssel und Datenfeld. Der Zugriff auf ein Element des Hashs ähnelt dem Zugriff auf eine Liste. Allerdings wird keine Nummer als Index verwendet, sondern der Schlüssel.

Werte hinzufügen und ändern

In der zweiten Zeile wird dem Dictionary kfz noch ein Wert hinzugefügt. Dadurch, dass es den Schlüssel hg noch nicht gibt, gibt es anschließend ein Element mehr. In der dritten Zeile wird wieder der Schlüssel hg verwendet, und daher bleibt die Anzahl der Elemente des Hashs gleich. Da hier ein Schlüssel verwendet wird, der schon existiert, wird nur der Inhalt dieses Elements verändert.

Zugriff auf Elemente

In der vierten Zeile wird eine Variable key mit dem Inhalt »hg« gefüllt, damit in der letzten Zeile darüber das entsprechende Dictionary-Element referenziert werden kann.

Löschen eines Elements

Mit der Funktion delete() können Einträge aus einer Hashvariablen wieder gelöscht werden. Dabei wird der Schlüssel als eindeutige Referenz angegeben. Der Aufruf sieht so aus:

del kfz[hh]

Damit wird der Eintrag mit dem Hamburger Kennzeichen aus dem Dictionary kfz gelöscht.

Mit der Funktion len() kann die Anzahl der Elemente eines Dictionaries bestimmt werden. Die Funktion has_key() kann ermitteln, ob es ein Element mit dem als Parameter angegebenen Schlüssel gibt.

print "Das Dictionary hat ", len(kfz), " Elemente"
if kfz.has_key("bi"):
    print kfz["bi"]
else:
    print "Bielefeld gibt es nicht."

In der ersten Zeile wird die Anzahl der Elemente im Dictionary ausgegeben. Danach wird geprüft, ob der Schlüssel »bi« im Dictionary vorkommt und eine entsprechende Ausgabe gemacht.

Klassen

Es klingt etwas überraschend, dass eine Interpretersprache, die keine feste Typbindung für Variablen kennt, objektorientierte Elemente besitzt. Tatsächlich ist es möglich, Klassen zu definieren. Klassen sind Datenstrukturen, die um Funktionen ergänzt werden, die auf die Datenelemente der Klasse einwirken.

Das Datum kann als Klasse dargestellt werden. Es enthält Tag, Monat und Jahr und den Wochentag. Als Funktion bietet sich an, ein paar Tage zum Datum hinzuzählen.

class Datum:
    tag = 1
    monat = 1
    jahr = 1970
    def addiere(self, tage):
        self.tag += tage
        # die weitere Berechnung spare ich mir hier

meintag = Datum() meintag.addiere(12)

Mit dem Schlüsselwort class beginnt die Klassendefinition. Es folgt der Name der Klasse und ein Doppelpunkt. Wie bei Python gewohnt, wird eingerückt, solange die Definition der Klasse dauert. Es folgen nun alle Mitglieder der Klasse. Hier sind es die Variablen tag, monat und jahr. Sie werden UNIX-typisch mit dem 1.~Januar 1970 vorbesetzt. Dann folgt die Funktion addiere(). Wie jede Definition einer Funktion beginnt auch diese mit dem Schlüsselwort def. Es folgt der Name der Funktion und die Klammer, die die Parameter enthält. Bei Klassenfunktionen gibt es immer mindestens einen Parameter. Dieser ist der Verweis auf die eigene Klasse. Daher wird dieser Parameter gern self genannt. Sie können aber auch einen anderen Namen nehmen.

Die objektorientierten Möglichkeiten von Python reichen erstaunlich weit. So gibt es die Möglichkeit, Konstruktoren und Destruktoren zu definieren. Operatoren können überladen werden und auch die Vererbung ist möglich. Im Rahmen dieses UNIX-Buchs interessiert allerdings bei den Fähigkeiten einer Skriptsprache mehr die schnelle Erstellung von Systemlösungen als die hohen Weihen des Software-Engineerings.

Referenzen und Kopien

Bei einer Zuweisung wird eine Kopie erstellt. Für Zahlen stimmt das auf jeden Fall. Wenn eine Zeichenkette einer anderen zugewiesen wird, stimmt das auch.

Sobald es sich aber um komplexere Objekte wie Listen, Tupel, Dictionaries oder von Klassen abgeleitete Objekte handelt, erzeugt Python kein zweites Objekt bei einer Zuweisung, sondern eine Referenz. Eine Referenz ist ein Verweis auf das Datenobjekt. Der Vorteil dieser Vorgehensweise ist, dass es schnell geht. Eine Referenz zu erstellen ist viel einfacher, als einen größeren Berg an Daten zu kopieren. Und in vielen Fällen ist ein Duplikat gar nicht notwendig. Eine Referenz reicht.

Der Nachteil ist, dass der Programmierer nicht immer im Kopf hat, dass zwei Variablen den gleichen Datenspeicher referenzieren. Das kann zu netten Verwechslungskomödien führen, die allerdings bei Programmen meist als Tragödien enden.

Das folgende Beispiel zeigt, wie sich eine Referenz auswirken kann:

Dictionary-Referenz per Zuweisung

kfz = {"sl":"Schleswig", "fl":"Flensburg","hh":"Hamburg"}
kfz["hg"] = "Bad Homburg"
kfz2 = kfz   # Hier wird eine Referenz gebildet!
kfz["hg"] = "Hochtaunuskreis"
key = "hg"
print "Schluessel = ", key, " Wert = ", kfz[key]
print "Schluessel = ", key, " Wert = ", kfz2[key]

Eigentlich müsste die Änderung, die nach der Zuweisung von kfz an kfz2 durchgeführt wurde nur auf kfz, nicht aber auf kfz2 wirken. Tatsächlich aber kommt in beiden Fällen das Ergebnis »Hochtaunuskreis« heraus.

Soll tatsächlich eine Kopie angefertigt werden, muss eine entsprechende Funktion verwendet werden. Zu diesem Zweck gibt es die Funktionen copy() und deepcopy() aus dem Modul copy.

Dictionary-Referenz per Zuweisung

kfz = {"sl":"Schleswig", "fl":"Flensburg","hh":"Hamburg"}
kfz["hg"] = "Bad Homburg"
kfz2 = copy(kfz)   # Hier wird ordentlich kopiert!
kfz["hg"] = "Hochtaunuskreis"
key = "hg"
print "Schluessel = ", key, " Wert = ", kfz[key]
print "Schluessel = ", key, " Wert = ", kfz2[key]

Und tatsächlich: Hier gibt es in der ersten Ausgabezeile »Hochtaunuskreis« und in der zweiten Zeile »Bad Homburg«.

Die Funktion deepcopy() müssen Sie einsetzen, wenn Sie verschachtelte Listen verwenden, damit auch die inneren Elemente kopiert werden.

Sollten Sie in Verwirrung geraten, ob zwei Variablen auf das gleiche Objekt verweisen oder vielleicht doch eine Kopie sind, können Sie beide mit dem Operator is vergleichen. Ist das Ergebnis wahr, sind es Referenzen auf das gleiche Objekt.

Dateien lesen und schreiben

Um Daten längerfristig festzuhalten, muss ein Programm sie in einer Datei abspeichern können. Um die geschriebenen Daten wiederzubekommen, wäre es schon ganz gut, wenn das Programm die Datei später auch wieder lesen könnte. Als Skriptsprache zur Unterstützung der Administrationstätigkeit ist das Auslesen von Protokolldateien natürlich von besonderem Interesse.

Öffnen einer Datei

Eine Datei muss vor ihrer Verwendung geöffnet werden. Die Funktion open() gibt ein Dateiobjekt zurück. Die Funktion open() braucht als Parameter natürlich den Namen der Datei, die bearbeitet werden soll, und die Art und Weise, wie die Datei vom Programm verwendet werden soll. Letzteres wird in einer Zeichenkette kodiert.

Die Funktion open() zum Öffnen einer Datei

Datei = open(Dateiname, [Optionsstring])

Die Optionen werden als Buchstaben in einer Zeichenkette übergeben.

Options-String bei open()

Option} Bedeutung
r Datei wird nur gelesen
w Datei wird neu geschrieben
a An die Datei wird angehängt
r+ Datei wird gelesen und geschrieben
w+ Datei wird gelesen und geschrieben
a+ Datei wird gelesen und geschrieben
b Datei wird im Binärmodus verwendet

Schließen der Datei

Nach Abschluss der Arbeiten mit der Datei muss sie geschlossen werden. Diesem Zweck dient die Funktion close(). Ihr Parameter ist das Handle, das die Funktion open() beim Öffnen der Datei zurückgegeben hat.

Die Funktion close() zum Schließen einer Datei

<Datei>.close()

Schreiben

Die Memberfunktion write() ermöglicht das Schreiben in eine Datei. Als Parameter erhält sie die zu schreibenden Daten. Das folgende Beispielprogramm öffnet eine Datei, schreibt eine Zeile hinein und schließt sie wieder.

In Datei schreiben

#!/usr/bin/python
try:
    Datei = open("testdata", "w")
    Datei.write("Wir schreiben in eine Textdatei\n")
    Datei.close();
except:
    print "oha!"

Lesen: readline()

Es würde Sie überraschen, wenn es keine Möglichkeit gäbe, die geschriebenen Daten auch wieder aus der Datei auszulesen. Die Memberfunktion readline() liest eine Zeile einer Textdatei in einen String. Sollte die Datei ähnlich übersichtlich sein, wie die oben erzeugte, können Sie auch mit einem Schlag alle Zeilen auf einmal in eine Stringliste einlesen. Die Funktion heißt dann readlines().

Aus Datei alle Zeilen auf einmal lesen

#!/usr/bin/python
try:
    Datei = open("testdata")
    TextZeilen = Datei.readlines()
    for Zeile in TextZeilen:
       print Zeile
    Datei.close()
except:
    # Ausnahmebehandlung
    print "oha! Ein Problem mit der Datei"

read()

Die allgemeine Funktion zum Lesen aus Dateien lautet read(). Als Parameter erhält sie die Anzahl der Bytes, die gelesen werden sollen. Wird kein Parameter angegeben, wird der Rest der Datei ab der aktuellen Position eingelesen.

Positionieren: seek()

Mit der Funktion seek() können Sie innerhalb einer Datei positionieren. Diese Funktion wird vor allem für Binärdateien verwendet. Damit können Datenblöcke abgelegt und unabhängig voneinander eingelesen werden. Der erste Parameter von seek() gibt an, um wie viele Bytepositionen der Dateizeiger versetzt wird. Der zweite Parameter gibt an, aus welcher Richtung der Zeiger versetzt wird.

Zweiter Parameter von seek()

Parameter} Berechnungsrichtung
0 Vom Anfang der Datei aus (Standardvorgabe)
1 Von der aktuellen Dateiposition aus
2 Vom Ende der Datei aus gesehen.

Daraus ergeben sich die folgenden Wirkungen von seek()-Aufrufen:

Datei.seek(129) # Positioniert auf das 129. Byte
Datei.seek(129,0) # Positioniert auf das 129. Byte
Datei.seek(12,1)  # Positioniert auf das 141. Byte (129+12)
Datei.seek(-2,2) # Positioniert auf das vorletzte Byte

Datenbankzugriffe

Von Python aus können Sie auf Datenbanken zugreifen. Dadurch steht es Ihnen offen, schnell größere Datenkorrekturen, Kontrollen oder Statistiken durchzuführen. Sie können natürlich auch komplexe Datenbankanwendungen schreiben.

Datenbankmodul

Grundsätzlich unterscheiden sich die Zugriffe auf die Datenbanken nicht nach der verwendeten Marke. Nur anhand des Moduls und des Verbindungsaufrufs unterscheiden sich MySQL, Oracle, DB/2 und Python. Für den Zugriff auf eine spezielle Datenbank benötigen Sie ein Modul. Als Beispiel soll hier die
Datenbank MySQL verwendet werden. Das passende Modul heißt MySQLdb und muss zu Anfang des Programms importiert werden. Hier und im Aufruf von connect() liegt die einzige Abhängigkeit von MySQL. Alle weiteren Befehle funktionieren mit anderen SQL-Datenbanken auch. Sie müssen also nur ein passendes Modul importieren, und Sie können mit Ihrer Lieblingsdatenbank arbeiten.

Das folgende Beispiel öffnet eine Datenbank, setzt einen INSERT-Befehl dort ab und schließt die Verbindung wieder.

Datenbankzugriff

#!/usr/bin/python
# -*- coding: Latin-1 -*-
import MySQLdb

conn = MySQLdb.connect(db="meinedb",user="ich", passwd="huhu") cursor = conn.cursor() cursor.execute("insert into buch " + \ " (nr, name, auflage) values " + \ "(4711, 'Einstieg in C++', 25000)") conn.close()

Über die Funktion connect() wird eine Verbindung geschaffen. Als Parameter dieser Verbindung sind die üblichen Angaben bei Datenbanken erforderlich. Unter db wird der Datenbankname angegeben. Es folgen der berechtigte Benutzer mit seinem Kennwort.

PostgreSQL

Würden Sie hier statt MySQL PostgreSQL verwenden wollen, würden sich die ersten zwei Zeilen ändern:

import pg
conn = pg.connect(db="meinedb",user="ich", passwd="huhu")

Die Verbindungsvariable wird benötigt, um einen Cursor zu bekommen. Über diesen Cursor wird dann mit Hilfe der Funktion execute() der Befehl an die Datenbank als einfache Zeichenkette übergeben.

Zeilenumbruch

Da die Zeichenkette sehr lang ist, wurde sie in mehrere Zeichenketten aufgebrochen, die einfach mit einem Pluszeichen verbunden sind. Am Ende der Zeile muss dann ein Backslash stehen, um Python mitzuteilen, dass der Befehl in der nächsten Zeile weitergeht. Sonst würde Python die Einrückung auch missverstehen.

SQL-Befehl selbst bauen

In diesem Fall sind die Werte der Übersicht halber direkt angegeben. Wenn Sie Variablen aus dem Programm heraus einfügen wollen, müssen Sie die Zeichenkette einfach zuvor mit den eigenen Werten bestücken. In den folgenden Zeilen wird eine Variable sqlbefehl mit einer formatierten Zeichenkette vorbelegt, in die die Variableninhalte von nr, name und aufl. eingebettet werden. Diese Zeichenkette wird der Funktion execute() übergeben, und schon sind diese Variablen in die Datenbank geschrieben.

sqlbefehl = "insert into buch  (nr, name, auflage) " + \
    " values (%i, %s, %i) % (nr, name, aufl)"
cursor.execute(sqlbefehl)

Die Befehle zum Einfügen, Ändern und Löschen sind auf diese Weise zu übermitteln, da sie letztlich nur aus einer einfachen Kommandozeile bestehen, die man vor dem Senden vom Programm her aufbereitet.

Etwas anders ist das Auslesen der Datenbank. In diesem Fall werden eventuell mehrere Zeilen von der Datenbank als Antwort kommen. Der Rahmen für eine Anfrage ist mit den anderen Befehlen gleich.

Datenbank auslesen

#!/usr/bin/python
# -*- coding: Latin-1 -*-
import MySQLdb

conn = MySQLdb.connect(db="meinedb",user="ich", passwd="huhu") cursor = conn.cursor() cursor.execute("select from buch") erg = cursor.fetchall() if erg: # Überschrift print " Nr Name Auflage" print "-----------------------------------" for nr, name, auflage in erg: print "%3i %30s %9i" % (nr, name, auflage) conn.close()

Nach dem Aufruf von execute() wird über die Funktion fetchall() die gesamte Ergebnismenge in den Speicher geholt. Das funktioniert natürlich nur dann, wenn diese Menge überschaubar ist.

Netzwerkzugriffe

Python unterstützt Sie mit Bibliotheken im Zugriff auf viele Internetserver. So gibt es die Möglichkeit, Websites zu steuern, Mails zu lesen und zu senden, Newsserver auszulesen oder Daten per FTP zu übertragen.

Auslesen einer Website

Das folgende kleine Programm öffnet die Website www.willemer.de Anschließend liest sie die vom Server gelieferte Seite Zeile für Zeile durch und speichert sie in einer lokalen Datei.

Sichern einer Website

import urllib
website = urllib.urlopen("http://www.willemer.de")
Zeilen = website.readlines()
website.close()
try:
    Datei = open("willemer.htm", "w")
    Datei.writelines(Zeilen)
    Datei.close()
except:
    print "Konnte Datei nicht schreiben"

Zugriff auf einen POP3-Server

Auch der Zugriff auf einen POP3-Server ist aus Python sehr einfach zu realisieren. Das folgende Beispiel liest die ersten 10 Zeilen jeder Mail aus und zeigt sie auf dem Bildschirm an. Damit Sie wirklich Freude an dem Programm haben, sollten Sie Ihre eigenen Daten für den POP3-Server, die Benutzerkennung und das Passwort verwenden.

Anfrage an POP3

#!/usr/bin/python
import poplib

MyMail = poplib.POP3('pop.1und1.de')
MyMail.user('pt1234567-aa')
MyMail.pass_('dasgehteuchgarnichtsan')
AnzMails = len(MyMail.list()[1])
for i in range(AnzMails):
    for j in MyMail.top(i+1, 10)[1]:
        print j

Es sind die POP3-Kommandos user pass, list und top als Memberfunktionen im Listing zu sehen. Mit den weiteren Kommandos retr und dele können alle von der RFC 1725 festgelegten Vorgänge durchgeführt werden.

Bei Fehlern bricht dieses Programm einfach ab. Durch die Ergänzung mit try und except können Sie die Fehler einfangen und eine ansprechende Fehlermeldung komponieren.

Tk, die grafische Oberfläche

Tk ist eine Bibliothek, die in Zusammenhang mit der Skriptsprache Tcl entstand. Tcl hat sich nicht auf breiter Basis durchsetzen können. Aber Tk ist eine beliebte Möglichkeit, auf einfache Art ein grafisches Programm zu erstellen.

Das folgende Beispielprogramm erzeugt ein Fenster mit einem Text und einem Button. Sobald der Button angeklickt wird, ist das Programm beendet.

Mini-Programm in Python mit Tk

#!/usr/bin/python
from Tkinter import *
# Callback-Funktion für den Button
def ende():
    sys.exit(0)

Fenster = Tk()
meinLabel = Label(Fenster, text = "Huhu")
meinButton = Button(Fenster, text = "Schluss", command = ende)
meinLabel.pack()
meinButton.pack()
Fenster.mainloop()

Callback-Funktion

Gleich zu Anfang wird eine Funktion ende() definiert, die nichts anderes tut, als das Programm zu beenden. Diese Funktion finden Sie bei der Definition des Buttons als command wieder. Drückt jemand auf den Button, löst er damit den Ruf von ende() aus.

Hauptfenster

Durch den Aufruf von Tk() wird das Hauptfenster des Programms erzeugt. Es befindet sich dann unter der Kontrolle der der Variablen Fenster. Bei der anschließenden Erzeugung von Label und Button wird Fenster als erster Parameter angegeben. Beide kommen also in das Fenster.

Widget- Ressourcen

Beim Erzeugen werden für Label und Button gleich ein paar Ressourcen gesetzt. Das erfolgt in Form einer Zuweisung, die sich innerhalb der Parameterklammern befindet. Mit text="Huhu" wird die text-Ressource des Labels mit dem String »Huhu« belegt.

In der Abbildung sehen Sie das Miniprogramm, wie es auf dem Bildschirm erscheint.

Und wieder LED- Vorwiderstand

Das nun folgende Programm ist etwas umfangreicher. Darin werden beispielhaft noch ein paar Techniken von Tk gezeigt. Damit und den Darstellungen von Tk in Perl, sollten Sie in der Lage sein, einfache Programme mit grafischer Oberfläche zu schreiben. Das Programm berechnet den nötigen Vorwiderstand für eine LED. Das Thema wurde auch schon bei der Vorstellung von JavaScript behandelt.

Grober Aufbau

Das Programm soll ein Menü enthalten. Darüber soll einerseits unter »Datei -- Quit« das Programm verlassen werden können. Über ein zweites Menü namens »Farbe« soll die Farbe der LED ausgewählt werden, für die der Widerstand berechnet wird. Dann werden noch zwei Eingabefelder gebraucht. Eines für die anliegende Gesamtspannung, das andere soll den Strom aufnehmen, der maximal fließen darf. Dann muss ein Label angelegt werden, in dem das Ergebnis erscheinen soll. Für den Start der Berechnung wird noch ein Button gebraucht, der darunter positioniert wird.

Grid

Um die Elemente anzuordnen, wird der Grid-Container verwendet, der allen Hauptfenster zu eigen ist. Achten Sie darauf, dass Sie nicht den Grid und die Funktion pack() im gleichen Fenster verwenden. Der Grid-Container ist einfach ein Raster. Für jedes Kontrollelement rufen Sie die Funktion grid() als Member-Funktion auf. Als Parameter übergeben Sie, wo das Element stehen soll. Dazu steht Ihnen »row«, also die Zeile, und »column«, also die Spalte, zur Verfügung. Ist einer der Werte 0, so muss er nicht explizit gesetzt werden. Der Aufruf sieht ein wenig originell aus, weil die Zuweisung in der Parameterklammer steht. Sie hatten beim Minimalprogramm aber schon gesehen, dass dies eine gängige Art ist, Ressourcen zu initialisieren.

lErgebnis.grid(row=2, column=1)

Der Aufbau des Fensters ist darüber hinaus geprägt von den Konstruktionsaufrufen der Widgets. Die Ressourcen werden belegt und die Fensterelemente in das passende Grid gelegt. In der folgenden Tabelle sehen Sie noch einmal das Grid, das dem Programm zu Grunde liegt.

row=0, column=0 row=0, column=1
row=1, column=0 row=1, column=1
row=2, column=0 row=2, column=1

Die Variablen für die Widgets werden nur benötigt, wenn später Interaktionen mit ihnen stattfinden. Das ist für die Entry-Elemente und das Ergebnis-Label wichtig. Für die Beschriftungen habe ich darum die Variable meinLabel wiederverwendet. Wenn die Beschriftung und Positionierung in einer Anweisung ausgeführt werden, könnte man die Variable komplett sparen. Auch die Button-Variable wird eigentlich nicht mehr gebraucht. Den Callback hat der Button bei seiner Erzeugung mitbekommen. Die Ressourcen des Buttons werden später nicht mehr geändert.

In der Callback-Funktion sehen Sie, wie mit der Memberfunktion get() die Werte aus den Entry-Feldern geholt werden. Sie sehen auch, dass das Programm keinerlei Fehler abfängt. In einem Programm, das ernsthaft unter die Leute kommt, würde man das natürlich ändern. Allerdings bringen diese Sicherheitsabfragen nichts Neues, darum ist es hier nicht dabei. Das Programm ist auch ohne diese schon reichlich lang.

Menübau

Der Aufbau des Menüs beginnt mit der Funktion Menu(). Auf diese Weise wird zunächst die Menüleiste aus dem Fenster erzeugt. Das bedeutet, die Menüleiste ist ein Unterfenster des Rahmenfensters. Später wird für jedes Drop-Down-Menü ein weiteres Menu() aus der Menüleiste entwickelt. Die einzelnen Menüleisten sind also Kinder des Menübalkens. Für jeden Eintrag im Dateimenü wird einmal add_command() aufgerufen. Über dessen command-Parameter wird die Callback-Funktion benannt, die aufgerufen wird, wenn der Menüpunkt angeklickt wird. In dieser Hinsicht unterscheidet sich ein Menüpunkt nicht von einem Button. Anschließend werden das Datei- und das Farbmenü mit add_cascade() wieder in den Menübaum eingehängt. Dieser wiederum wird an der Menüeigenschaft des Fensters eingehängt.

Fenster["menu"] = menubar

Ressourcen ändern

Sie sehen hier, wie die Datenstruktur Dictionary verwendet wird, um Ressourcen eines Widgets zu verwalten und nachträglich zu ändern. Wenn der Wert einer Ressource geändert wird, können Sie den Namen der Ressource als Schlüssel benutzen. Die gleiche Technik sehen Sie in der Funktion Calc() um die Ressource text des Labels lErgebnis zu ändern. Alternativ zum Dictionary könnten Sie auch die Funktion configure() verwenden. Beim Aufruf der Funktion configure() wird wie bei der Initialisierung eine Zuweisung in der Klammer verwendet. Die beiden folgenden Zeilen sind also austauschbar.

lErgebnis["text"] = "---"
lErgebnis.configure(text="---")

Farbige Radiobuttons

Das Farbmenü ist noch ein klein wenig anders aufgebaut. Hier wurde ein Radiobutton ins Menü gehängt. Als kleiner Gag werden die einzelnen Farben auch im Menü farbig hinterlegt. Die Radiobuttons korrespondieren mit einer Variable, die speziell behandelt wird. Hier ist es eine Fließkommavariable, die aus dem Tk mit dem Aufruf DoubleVar() erzeugt wird. Diese wird jedem Radiobutton als Parameter variable mitgegeben. Jeder Radiobutton hat als value-Parameter die Voltzahl, die an der jeweiligen LED abfällt. Dieser Wert wird bei Anwahl des Radiobuttons direkt in die Variable geschrieben.

LED-Vorwiderstandsberechnung mit Python und Tk

#!/usr/bin/python
# -*- coding: Latin-1 -*-
from Tkinter import *
# Callback-Funktion für den Button. Berechnet das Ergebnis
def Calc():
   Udiff = float(eUges.get())-Uled.get()
   Imax  = float(eImax.get())
   if Imax>0:
       lErgebnis["text"] = str((Udiff/Imax)*1000)
   else:
       lErgebnis["text"] = "---"
# Callback für den Quit-Menüeintrag
def Ende():
    sys.exit(0)

Fenster = Tk() # Fenster erzeugen # Uges - Label und Eingabefeld meinLabel = Label(Fenster, text = "Uges:") meinLabel.grid(row=0) eUges = Entry(Fenster) eUges.grid(row=0, column=1)

# Imax - Label und Eingabefeld meinLabel = Label(Fenster, text = "Imax:") meinLabel.grid(row=1) eImax = Entry(Fenster) eImax.grid(row=1, column=1)

# Ergebniszeile - Label und Ergebnislabel Label(Fenster, text = "Ohm").grid(row=2) lErgebnis = Label(Fenster, text = "") lErgebnis.grid(row=2, column=1) # Berechnungs-Button meinButton = Button(Fenster, text="Berechne", command=Calc) meinButton.grid(row=3, column=1)

# Menü wird erstellt menubar = Menu(Fenster) mdatei = Menu(menubar, tearoff=0) mdatei.add_command(label="Quit", command=Ende) menubar.add_cascade(label="Datei", menu=mdatei)

mfarbe = Menu(menubar, tearoff=0) # Die Radiobuttons füllen die Variable Uled Uled = DoubleVar() mfarbe.add_radiobutton(label="rot", variable=Uled,value=1.6, \ background="red") mfarbe.add_radiobutton(label="grün", variable=Uled,value=2.1, \ background="green") mfarbe.add_radiobutton(label="gelb", variable=Uled,value=2.2,\ background="yellow") mfarbe.add_radiobutton(label="blau", variable=Uled,value=2.9,\ background="blue") mfarbe.add_radiobutton(label="weiß", variable=Uled,value=4.0,\ background="white") menubar.add_cascade(label="Farbe", menu=mfarbe) # Das Menü wird eingehängt Fenster["menu"] = menubar # Nun kann das Programm laufen Fenster.mainloop()

Das Programmfenster ist nicht groß, aber sieht mit dem farbigen Menü natürlich originell aus.


Homepage (C) Copyright 2009 Arnold Willemer