print("Hallo")
Hallo
Unter Eingabe (Input) versteht man die Eingabe von Informationen von der Tastatur bzw. aus einer Datei, um diese in einem Programm verarbeiten zu können. Unter Ausgabe versteht man die Ausgabe von Informationen am Bildschirm bzw. in eine Datei (also z.B. Ergebnisse einer Berechnung). Im Folgenden werden wir sehen, wie wir Strings für die Ausgabe formatieren können und wie wir Textdateien lesen bzw. schreiben können.
Wir haben bereits die print
-Funktion kennengelernt, welche Strings (und andere Objekte) als Text am Bildschirm ausgeben kann. Im einfachsten Fall kann so ein String ausgegeben werden:
print("Hallo")
Hallo
Auch Zahlen kann man als Argument für print
verwenden:
print(55)
55
Mit der Funktion str
kann man beliebige Objekte (also auch z.B. Ganzzahlen) in einen String umwandeln:
str(55)
'55'
Die print
-Funktion kann beliebig viele Argumente entgegennehmen. Sie gibt dann alle Argumente, getrennt von Leerzeichen, am Bildschirm aus.
= 5
a = 10
b print(a, "+", b, "=", a + b) # fünf Argumente
5 + 10 = 15
Wie wir bereits wissen, kann man mehrere Strings mit +
verketten. Daher könnte man obige Ausgabe auch durch Ausgabe eines einzigen Strings durch Verketten von einzelnen Strings erzeugen:
print(str(a) + " + " + str(b) + " = " + str(a + b)) # ein Argument
5 + 10 = 15
Sogenannte f-Strings sind ganz normale Strings, man kann aber bei ihrer Erzeugung beliebige Ausdrücke verwenden, die dann ausgewertet in den String eingesetzt werden. Man definiert einen f-String genau wie einen normalen String mittels Anführungszeichen, stellt aber ein f
voran, also z.B.:
f"Hallo"
'Hallo'
Sinnvoll sind f-Strings nur dann, wenn man auch tatsächlich Ausdrücke integriert, welche innerhalb von geschwungenen Klammern {}
angegeben werden. Alle Ausdrücke werden ausgewertet und in den String eingesetzt (interpoliert):
= "World"
name f"Hello {name}!"
'Hello World!'
Den fertigen String kann man dann einfach mit print
am Bildschirm ausgeben. Das Beispiel aus dem vorigen Abschnitt kann man daher wie folgt anschreiben:
print(f"{a} + {b} = {a + b}")
5 + 10 = 15
Ausdrücke, wie z.B. Zahlen, können optional auch speziell formatiert werden. Sehen wir uns zunächst an, wie die Kreiszahl \(\pi\) standardmäßig ausgegeben wird:
import math
print(f"π ≈ {math.pi}")
π ≈ 3.141592653589793
Mit einem optionalen Doppelpunkt und einem sogenannten Format Specifier innerhalb der geschwungenen Klammern kann ein Ausdruck gezielt formatiert werden. Das folgende Beispiel formatiert die Kommazahl Pi so, dass sie mit drei Nachkommastellen ausgegeben wird:
print(f"π ≈ {math.pi:.3f}")
π ≈ 3.142
Oder mit 16 Nachkommastellen:
print(f"π ≈ {math.pi:.16f}")
π ≈ 3.1415926535897931
Die minimale Feldbreite kann mit einer Zahl direkt nach dem Doppelpunkt spezifiziert werden, im folgenden Beispiel soll diese 15 Zeichen betragen:
print(f"π ≈ {math.pi:15.3f}")
π ≈ 3.142
Alle Möglichkeiten, die Format Specifier innerhalb der geschwungenen Klammern bieten, finden sich in der offiziellen Dokumentation (inklusive einer Menge Beispiele).
Die Funktion open
gibt ein Datei-Objekt zurück, welches zum Lesen oder Schreiben von Dateien verwendet werden kann (die im Beispiel verwendete Datei test.txt
ist hier verfügbar):
= open("test.txt", "w") f
Das erste Argument ist der Dateiname, und das zweite Argument beschreibt den Modus ("r"
lesen, "w"
schreiben, "a"
hinzufügen). Standardmäßig wird der Modus "r"
angenommen, wenn das Argument nicht übergeben wird.
Mit dem Datei-Objekt f
kann man dann von der Datei lesen bzw. in die Datei schreiben.
Nach Beendigung aller Lese- und Schreiboperationen muss man das Datei-Objekt wieder schließen:
f.close()
Es ist sinnvoll, alle Datei-Operationen in einem with
-Block durchzuführen; so wird die Datei bei Verlassen des Blocks automatisch geschlossen:
with open("test.txt") as f:
= f.read() data
Zu Beachten ist noch, dass der Dateiname als String übergeben wird. Dieser enthält entweder den vollständigen Pfad der zu öffnenden Datei (z.B. "C:/Program Files/Test Program/test.txt"
), oder nur den Dateinamen. Im letzteren Fall wird dann angenommen, dass sich die Datei im Arbeitsverzeichnis befindet.
Pfade sollten immer mit einem normalen /
getrennt werden und nicht wie unter Windows üblich mit einem verkehrten \
.
Die Methode read
eines Datei-Objektes liest die gesamte Datei ein und gibt den Inhalt als String zurück:
= open("test.txt")
f = f.read()
text print(text)
Hello!
This is just a test file containing some random text.
Nice!
Der Inhalt einer Datei kann immer nur ein Mal gelesen werden. Wenn bereits der gesamte Inhalt gelesen wurde, befindet sich der sogenannte Dateizeiger am Ende der Datei. Wenn dann nochmals gelesen wird, wird nur mehr ein leerer String zurückgegeben:
# Ende der Datei bereits erreicht f.read()
''
Möchte man die Datei erneut lesen, muss man sie schließen und kann sie dann wieder erneut öffnen:
# schließt Datei (notwendig wenn man kein with verwendet) f.close()
Die Methode readline
liest eine Zeile aus der Datei:
with open("test.txt") as f:
print("1. Zeile: ", f.readline(), end="")
print("2. Zeile: ", f.readline(), end="")
print("3. Zeile: ", f.readline(), end="")
1. Zeile: Hello!
2. Zeile:
3. Zeile: This is just a test file containing some random text.
In einer Schleife kann man die Datei Zeile für Zeile auslesen, in dem man über das Datei-Objekt iteriert:
with open("test.txt") as f:
for line in f:
print(line, end="")
Hello!
This is just a test file containing some random text.
Nice!
So kann man einzelne Zeilen einfach manipulieren, z.B. um Zeilennummern auszugeben (die nicht in der Datei selbst sind):
with open("test.txt") as f:
for no, line in enumerate(f):
print(no, line, end="")
0 Hello!
1
2 This is just a test file containing some random text.
3
4 Nice!
In der for
-Schleife wird hier nicht direkt über f
, sondern über enumerate(f)
iteriert. Diese Funktion zählt die Schleifendurchläufe mit und gibt ein Tupel bestehend aus dem aktuellen Wert des Schleifenzählers sowie der aktuellen Zeile zurück.
Text in Dateien schreiben funktioniert sehr ähnlich – man öffnet die Datei im "w"
-Modus und übergibt der write
-Methode den gewünschten Inhalt als String:
with open("test2.txt", "w") as f:
"Das ist ein Test.\nSo kann man einfach\nText\nin Dateien schreiben.") f.write(
In diesem Beispiel steht die Escape-Sequenz \n
für einen Zeilenumbruch (neue Zeile).
Mit den bis jetzt vorgestellten Mitteln können wir bereits CSV1-Dateien einlesen und rudimentäre Statistiken rechnen. CSV-Dateien werden häufig verwendet, um tabellarische Daten abzuspeichern. Diese Dateien sind reine Textdateien, in denen die Variablen (Spalten) durch Kommas getrennt sind und die einzelnen Datensätze zeilenweise vorliegen.
Im Folgenden werden drei Möglichkeiten zum Lesen einer CSV-Datei vorgestellt (die Beispieldatei correlation.csv
ist hier verfügbar). Die erste Methode verwendet Python ohne spezielle Module, die zweite Methode ist eine Verallgemeinerung der ersten. Die dritte und einfachste Variante verwendet das Package pandas, welches wir in dieser Lehrveranstaltung nicht genauer kennenlernen werden (sie wird der Vollständigkeit halber aber trotzdem erwähnt).
Wir starten mit einer leeren Liste data
. Dieser Liste fügen wir den Inhalt jeder Zeile schrittweise (mittels append
) hinzu. Eine Zeile wird dabei als Liste mit zwei Strings abgebildet.
= [] # leere Liste
data with open("correlation.csv") as f:
for row in f:
",")) data.append(row.strip().split(
data
[['essay', 'hours'],
['61.6754974920745', '10.6303372921189'],
['69.5450056362295', '7.28522617959232'],
['48.2293039713449', '5.05204775449098'],
['70.6786516311817', '2.88661436120476'],
['59.8996225857332', '9.54501229482367'],
['61.1620237718455', '11.3108384701452'],
['67.6247016928604', '7.46507180351913'],
['64.7790589873963', '8.47127906794298'],
['63.207063456166', '8.71537345316006'],
['49.6910817003072', '6.20347356947365'],
['63.7189196026189', '4.77251550782322'],
['72.2425933666743', '10.9815424018851'],
['70.5862210579123', '5.2215409766568'],
['58.6398615751171', '6.85848450383968'],
['58.7153800614887', '9.7984118965962'],
['67.3999698058767', '9.49072930246925'],
['60.7037631406063', '6.51736420324962'],
['60.931351175695', '11.8021326615165'],
['62.3401801239333', '8.96313112993931'],
['59.9662288209405', '5.42249029575092'],
['52.1619843495503', '6.40972025602273'],
['76.5879640890472', '15.0104773734972'],
['60.9196973933278', '8.07064211676739'],
['66.6330159660378', '10.9720986214915'],
['73.6195367228337', '14.7776461317624'],
['60.2224731091917', '5.2455561967939'],
['59.257246898708', '8.67216132385057'],
['51.9302907572568', '8.55546259639567'],
['59.4301075638833', '6.08144370899007'],
['69.4087175381595', '7.42190548469444'],
['65.2986136310666', '12.3137937416164'],
['60.2838297249765', '9.93443882388444'],
['60.8535237978012', '7.79529820172183'],
['71.6333469504558', '6.5627956116459'],
['69.1407939072155', '10.2828636303044'],
['66.4753904156445', '5.11639249646656'],
['63.0477561140632', '8.66268357519631'],
['68.1678280737943', '6.59320568183171'],
['64.7480342462125', '3.70537792316693'],
['68.2804343717536', '12.9178683539958'],
['60.4052387002632', '8.6962361085862'],
['64.6313248038771', '11.2150596156186'],
['58.2594898681359', '6.83244891007452'],
['52.2352473953415', '8.62308388223269'],
['79.8777504975499', '7.84368345377415']]
Nun können die Daten in eine Struktur umgewandelt werden, die sich besser für nachfolgende Berechnungen eignet (also inbesondere werden die Zahlen, die als Strings vorliegen, mit der Funktion float
in Kommazahlen umgewandelt).
= [[], []] # two empty lists for the two columns
cols for row in data[1:]: # skip first row (header)
0].append(float(row[0])) # first column
cols[1].append(float(row[1])) # second column cols[
Nun stehen die beiden Spalten in der Liste cols
zur weiteren Verfügung. Diese Liste hat zwei Elemente:
len(cols)
2
Die beiden Einträge in cols
sind ebenfalls Listen:
type(cols[0]), type(cols[1])
(list, list)
Die Länge beider Listen entspricht der Anzahl an Zeilen in der CSV-Datei (ohne Kopfzeile):
len(cols[0]), len(cols[1])
(45, 45)
Die Elemente in diesen beiden Listen sind Zahlen:
0] cols[
[61.6754974920745,
69.5450056362295,
48.2293039713449,
70.6786516311817,
59.8996225857332,
61.1620237718455,
67.6247016928604,
64.7790589873963,
63.207063456166,
49.6910817003072,
63.7189196026189,
72.2425933666743,
70.5862210579123,
58.6398615751171,
58.7153800614887,
67.3999698058767,
60.7037631406063,
60.931351175695,
62.3401801239333,
59.9662288209405,
52.1619843495503,
76.5879640890472,
60.9196973933278,
66.6330159660378,
73.6195367228337,
60.2224731091917,
59.257246898708,
51.9302907572568,
59.4301075638833,
69.4087175381595,
65.2986136310666,
60.2838297249765,
60.8535237978012,
71.6333469504558,
69.1407939072155,
66.4753904156445,
63.0477561140632,
68.1678280737943,
64.7480342462125,
68.2804343717536,
60.4052387002632,
64.6313248038771,
58.2594898681359,
52.2352473953415,
79.8777504975499]
1] cols[
[10.6303372921189,
7.28522617959232,
5.05204775449098,
2.88661436120476,
9.54501229482367,
11.3108384701452,
7.46507180351913,
8.47127906794298,
8.71537345316006,
6.20347356947365,
4.77251550782322,
10.9815424018851,
5.2215409766568,
6.85848450383968,
9.7984118965962,
9.49072930246925,
6.51736420324962,
11.8021326615165,
8.96313112993931,
5.42249029575092,
6.40972025602273,
15.0104773734972,
8.07064211676739,
10.9720986214915,
14.7776461317624,
5.2455561967939,
8.67216132385057,
8.55546259639567,
6.08144370899007,
7.42190548469444,
12.3137937416164,
9.93443882388444,
7.79529820172183,
6.5627956116459,
10.2828636303044,
5.11639249646656,
8.66268357519631,
6.59320568183171,
3.70537792316693,
12.9178683539958,
8.6962361085862,
11.2150596156186,
6.83244891007452,
8.62308388223269,
7.84368345377415]
Mit diesen beiden Listen kann man jetzt also Berechnungen durchführen. Beispielsweise kann man die Spaltenmittelwerte so ausrechnen:
sum(cols[0]) / len(cols[0])
63.44991370093669
sum(cols[1]) / len(cols[1])
8.349021354368455
Diese Lösung ist allerdings alles andere als ideal. Erstens sollte man immer bereits existierende Lösungen verwenden und nicht alles von Grund auf neu entwickeln (es gibt in Python wie bereits erwähnt ein eigenes csv
-Modul, und das Package pandas
ist für solche Aufgaben geradezu prädestiniert). Zweitens ist diese Lösung auch sehr auf die konkrete Datei angepasst, z.B. funktioniert der Ansatz nur für eine Datei mit exakt zwei Spalten.
Eine verallgemeinerte Lösung für eine beliebige Anzahl an Spalten sieht wie folgt aus:
with open("correlation.csv") as f:
= f.readline().strip().split(",") # erste Zeile
header
= {} # dict mit einem Eintrag pro Spalte
data for name in header:
= [] # Key ist der Spaltenname, Value eine leere Liste
data[name]
for row in f: # restliche Zeilen
= row.strip().split(",")
values for h, v in zip(header, values):
float(v)) # füge zur jeweiligen Liste hinzu data[h].append(
Hier werden die Variablennamen aus der ersten Zeile (der Kopfzeile) gelesen. Die Daten werden dann in ein Dictionary geschrieben, wobei die Werte der Spalten zu den richtigen Dictionary-Einträgen (Listen) hinzugefügt werden. Die Funktion zip
kombiniert die Werte von header
und values
in ein Tupel, die dann innerhalb der Schleife als h
bzw. v
zur Verfügung stehen.
data
{'essay': [61.6754974920745,
69.5450056362295,
48.2293039713449,
70.6786516311817,
59.8996225857332,
61.1620237718455,
67.6247016928604,
64.7790589873963,
63.207063456166,
49.6910817003072,
63.7189196026189,
72.2425933666743,
70.5862210579123,
58.6398615751171,
58.7153800614887,
67.3999698058767,
60.7037631406063,
60.931351175695,
62.3401801239333,
59.9662288209405,
52.1619843495503,
76.5879640890472,
60.9196973933278,
66.6330159660378,
73.6195367228337,
60.2224731091917,
59.257246898708,
51.9302907572568,
59.4301075638833,
69.4087175381595,
65.2986136310666,
60.2838297249765,
60.8535237978012,
71.6333469504558,
69.1407939072155,
66.4753904156445,
63.0477561140632,
68.1678280737943,
64.7480342462125,
68.2804343717536,
60.4052387002632,
64.6313248038771,
58.2594898681359,
52.2352473953415,
79.8777504975499],
'hours': [10.6303372921189,
7.28522617959232,
5.05204775449098,
2.88661436120476,
9.54501229482367,
11.3108384701452,
7.46507180351913,
8.47127906794298,
8.71537345316006,
6.20347356947365,
4.77251550782322,
10.9815424018851,
5.2215409766568,
6.85848450383968,
9.7984118965962,
9.49072930246925,
6.51736420324962,
11.8021326615165,
8.96313112993931,
5.42249029575092,
6.40972025602273,
15.0104773734972,
8.07064211676739,
10.9720986214915,
14.7776461317624,
5.2455561967939,
8.67216132385057,
8.55546259639567,
6.08144370899007,
7.42190548469444,
12.3137937416164,
9.93443882388444,
7.79529820172183,
6.5627956116459,
10.2828636303044,
5.11639249646656,
8.66268357519631,
6.59320568183171,
3.70537792316693,
12.9178683539958,
8.6962361085862,
11.2150596156186,
6.83244891007452,
8.62308388223269,
7.84368345377415]}
Diese Lösung funktioniert also bereits mit einer beliebigen Spaltenanzahl, setzt aber voraus, dass es eine Kopfzeile gibt. Die Spaltenmittelwerte können dann wie folgt berechnet werden:
sum(data["essay"]) / len(data["essay"])
63.44991370093669
sum(data["hours"]) / len(data["hours"])
8.349021354368455
Das Package pandas
eignet sich ideal zum Verarbeiten von tabellarischen Daten. Es beinhaltet auch Funktionen zum Lesen von Dateien. Damit würde der Code wie folgt aussehen:
import pandas as pd
= pd.read_csv("correlation.csv") data
data
essay | hours | |
---|---|---|
0 | 61.675497 | 10.630337 |
1 | 69.545006 | 7.285226 |
2 | 48.229304 | 5.052048 |
3 | 70.678652 | 2.886614 |
4 | 59.899623 | 9.545012 |
5 | 61.162024 | 11.310838 |
6 | 67.624702 | 7.465072 |
7 | 64.779059 | 8.471279 |
8 | 63.207063 | 8.715373 |
9 | 49.691082 | 6.203474 |
10 | 63.718920 | 4.772516 |
11 | 72.242593 | 10.981542 |
12 | 70.586221 | 5.221541 |
13 | 58.639862 | 6.858485 |
14 | 58.715380 | 9.798412 |
15 | 67.399970 | 9.490729 |
16 | 60.703763 | 6.517364 |
17 | 60.931351 | 11.802133 |
18 | 62.340180 | 8.963131 |
19 | 59.966229 | 5.422490 |
20 | 52.161984 | 6.409720 |
21 | 76.587964 | 15.010477 |
22 | 60.919697 | 8.070642 |
23 | 66.633016 | 10.972099 |
24 | 73.619537 | 14.777646 |
25 | 60.222473 | 5.245556 |
26 | 59.257247 | 8.672161 |
27 | 51.930291 | 8.555463 |
28 | 59.430108 | 6.081444 |
29 | 69.408718 | 7.421905 |
30 | 65.298614 | 12.313794 |
31 | 60.283830 | 9.934439 |
32 | 60.853524 | 7.795298 |
33 | 71.633347 | 6.562796 |
34 | 69.140794 | 10.282864 |
35 | 66.475390 | 5.116392 |
36 | 63.047756 | 8.662684 |
37 | 68.167828 | 6.593206 |
38 | 64.748034 | 3.705378 |
39 | 68.280434 | 12.917868 |
40 | 60.405239 | 8.696236 |
41 | 64.631325 | 11.215060 |
42 | 58.259490 | 6.832449 |
43 | 52.235247 | 8.623084 |
44 | 79.877750 | 7.843683 |
Die Spaltenmittelwerte kann man dann wie folgt berechnen:
data.mean()
essay 63.449914
hours 8.349021
dtype: float64
Erstellen Sie eine Liste lst
, welche die geraden Zahlen zwischen 0 und 100 (inklusive) beinhaltet, und speichern Sie diese Zahlen in eine Datei ue1.txt
. In der Datei soll jede Zahl in einer eigenen Zeile stehen.
Zahlen sollten vor dem Schreiben in die Datei mit der Funktion str
in Strings umgewandelt werden. Das Zeichen für einen Zeilenumbruch lautet \n
. Sie können z.B. eine for
-Schleife über die Zahlenliste machen und die einzelnen Elemente nacheinander in die Datei schreiben. Alternativ können Sie auch die Liste in einen richtig formatierten String umwandeln (die String-Methode join
ist hier hilfreich) und diesen dann in die Datei schreiben.
Verwenden Sie wieder die Liste lst
aus Übung 1, aber schreiben Sie die Zahlen nun so in eine Datei ue2.txt
, dass diese durch Kommas getrennt in einer Zeile stehen.
Das Spiel Scrabble eignet sich hervorragend, um über die Existenz von Wörtern zu diskutieren. Zumindest für die englische Ausgabe gibt es eine offizielle Wortliste, die man konsultieren kann, wenn man nicht sicher ist, ob es sich bei einer Kreation um ein gültiges Wort handelt oder nicht. Alle Wörter in dieser Datenbank können als Textdatei heruntergeladen werden.
Für diese Übung laden Sie sich diese Datei herunter und speichern Sie sie in Ihrem Arbeitsverzeichnis ab. Lesen Sie die Datei dann in Python ein und finden Sie heraus, wie viele Wörter (Zeilen) sich in der Datei befinden.
Iterieren Sie mit einer for
-Schleife über das Datei-Objekt und zählen Sie die Schleifendurchläufe mit. Am Ende der Schleife (d.h. am Ende der Datei) entspricht dann ihr Zähler der Zeilenanzahl der Datei (d.h. der Anzahl der Wörter). Beachten Sie, dass die ersten paar Zeilen in der Datei keine Wörter beinhalten!
Wenn man es ganz exakt machen möchte, sollte man auch noch überprüfen, ob die aktuelle Zeile auch tatsächlich ein Wort enthält (also keine Leerzeile ist).
Verwenden Sie die Wörter-Datei aus Übung 3 und finden Sie heraus, wie viele Wörter mit mehr als 14 Buchstaben in der Liste enthalten sind (also Wörter mit 15 Buchstaben oder mehr).
Wenn Sie die Datei Zeile für Zeile einlesen, entfernen Sie unsichtbare Zeichen (wie z.B. Zeilenumbruch) mit der Methode strip
, bevor Sie die Länge des aktuellen Wortes bestimmen (ansonsten ist die Länge immer um 1 größer als die Länge des Wortes, weil der Inhalt einer Zeile z.B. abandon\n
lautet, und \n
wird als ein Zeichen gezählt). Erhöhen Sie Ihren Zähler nur, wenn die Länge des aktuellen Wortes (ohne Zeilenumbruch) größer als 14 ist.
Comma-Separated Values↩︎