Fehlermeldungen#
Bis hierher haben sich bestimmt schon einmal Fehler in Ihren Code geschlichen, worauf Python Sie (hoffentlich) mit einer Fehermeldung aufmerksam gemacht. In einer Fehlermeldung spezifiziert Python sowohl die Fehlerquelle, also wo sich der Fehler befindet, als auch den Fehlertyp, also was der Fehler konkret ist. An dieser Stelle wollen wir Sie für die typischen Fehler sensiblisieren und Ihnen zeigen wie Sie diese beheben können.
SyntaxError#
Wenn Sie eine neue Sprache lernen – sei es Englisch, Französisch oder eine Programmiersprache wie Python – dann gibt es bestimmte Regeln, die Sie beachten müssen. Diese Regeln nennt man Syntax.
Definition
Die Syntax ist die Grammatik einer Programmiersprache. Sie legt fest, wie ein Programm geschrieben werden muss, damit der Computer es versteht.
Warum ist Syntax wichtig? Stellen Sie sich vor, Sie sagen zu jemandem: “Haben wir morgen Kino gehen?” Das klingt falsch, weil die Grammatik nicht stimmt. Ähnlich ist es in Python: Wenn Sie sich nicht an die Regeln halten, wirft Python eine Fehlermeldung. In diesem Fall einen \(\texttt{SyntaxError}\). Ein Beispiel dafür ist der folgende Code:
print "Hallo Welt!"
Cell In[1], line 1
print "Hallo Welt!"
^
SyntaxError: Missing parentheses in call to 'print'. Did you mean print(...)?
Der Code führt zu einer Fehlermeldung. Warum? Weil \(\texttt{print}\) Klammern braucht: \(\texttt{print("Hallo, Welt!")}\).
In Python werden Fehler normalerweise direkt im Ausgabe- oder Fehlerbereich angezeigt. Dort werden Sie eine Fehlermeldung sehen, die den Fehlerort und eine Beschreibung des Problems enthält. Die Fehlermeldung besteht häufig aus zwei Teilen: der Fehlerbeschreibung und dem Fehlerort, wodurch die Fehlersuche und -behebung erleichtert wird.
Fehlerbeschreibung: Hier wird der genaue Fehlertyp genannt, hier \(\texttt{SyntaxError}\), und eine kurze Erklärung, was das Problem ist (hier Missing parentheses in call to ‘print’.).
Fehlerort: Der Codeabschnitt, in dem der Fehler auftritt, wird angezeigt, wobei oft der genaue Zeile des Fehlers (z.B. eine fehlende Klammer oder ein falsches Schlüsselwort) durch einen Indikator markiert wird.
In den nachfolgenden Abschnitte geben wir Ihnen fehlerhafte Codeabschnitte vor. Ihre Aufgabe besteht darin den Fehler zu identifizieren und zu korrigieren. Nutzen Sie dazu die Rückmeldung in Form einer Fehlermeldnug von Python.
Aufgabe 1.1
Passen Sie den Code an, sodass die Fehlermeldung behoben wird.
# falscher Code
import np
x = np.array([1, 2, 3])
---------------------------------------------------------------------------
ModuleNotFoundError Traceback (most recent call last)
Cell In[1], line 2
1 # falscher Code
----> 2 import np
4 x = np.array([1, 2, 3])
ModuleNotFoundError: No module named 'np'
Hinweis
\(\texttt{NameError: name 'np' is not defined}\) deutet darauf hin, dass NumPy nicht richtig importiert worden ist.
Lösung
import numpy as np # Korrektur
x = np.array([1, 2, 3])
Aufgabe 1.2
Passen Sie den Code an, sodass die Fehlermeldung behoben wird.
# falscher Code
import numpy as np
A = np.array([[1, 2, 3], [4, 5]])
print(A.shape)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[2], line 4
1 # falscher Code
2 import numpy as np
----> 4 A = np.array([[1, 2, 3], [4, 5]])
5 print(A.shape)
ValueError: setting an array element with a sequence. The requested array has an inhomogeneous shape after 1 dimensions. The detected shape was (2,) + inhomogeneous part.
Hinweis
\(\texttt{ValueError: setting an array element with a sequence.}\) deutet darauf hin, dass \(A\) nicht korrekt definiert wurde.
Lösung
An dieser Stelle ist es wichtig, dass die beiden Zeilen gleich lang sind. Dies können Sie erreichen, indem Sie bei der zweiten Zeile ein Element hinzufügen (Option 1) oder bei der ersten Zeile ein Element entfernen (Option 2).
import numpy as np
# Option 1
A = np.array([[1, 2, 3], [4, 5, 6]]) # Korrektur
print(A.shape)
# Option 2
A = np.array([[1, 2], [4, 5]]) # Korrektur
print(A.shape)
Aufgabe 1.3
Passen Sie den Code an, sodass die Fehlermeldung behoben wird.
# falscher Code
def greet():
return "Hallo!"
print(greet)
<function greet at 0x000001354B471DA0>
Hinweis
\(\texttt{<function greet at 0x...>}\) deutet darauf hin, dass die Funktion nicht richtig aufgerufen wird.
Lösung
def greet():
return "Hallo!"
print(greet()) # Korrektur: die Klammern haben gefehlt
Übersicht - typische Fehlerquellen#
Zum Abschluss möchten wir Ihnen noch eine Liste der häufigsten \(\texttt{SyntaxError}\) mit auf den Weg geben.
Fehler |
Beispiel |
Erklärung |
|---|---|---|
Vergessene Klammern |
\(\texttt{print("Hello World"}\) |
Eine schließende Klammer fehlt. |
Falsche Klammern verwendet |
\(\texttt{if [x > 10]:}\) |
Statt runder Klammern \(\texttt{()}\) wurden eckige Klammern \(\texttt{[]}\) verwendet. |
Falsche Einrückung |
\(\texttt{if x > 10:} \\\\ \texttt{print(x)}\) |
Einrückung muss konstant sein. |
Ungültiger Variablenname |
\(\texttt{2x = 10}\) |
Variablennamen dürfen nicht mit einer Zahl beginnen. |
Falsche String-Begrenzung |
\(\texttt{'Hello World"}\) |
Ein String muss mit dem gleichen Zeichentyp abgeschlossen werden (z.B. beide \(\texttt{'}\) oder beide \(\texttt{"}\)). |
Fehlender Operator |
\(\texttt{x 10}\) |
Ein Operator zwischen Variablen fehlt (z.B. \(\texttt{x + 10}\)). |
Verwendung von reservierten Wörtern |
\(\texttt{def = 10}\) |
\(\texttt{def}\) ist ein reserviertes Schlüsselwort und kann nicht als Variablenname verwendet werden. |
Zu viele Klammern |
\(\texttt{if (x > 10)):}\) |
Zu viele schließende Klammern. |
Falsche Anzahl von Argumenten |
\(\texttt{print("Hello", 10)}\) |
Eine Funktion erhält nicht die erforderliche Anzahl von Argumenten. |
RuntimeError#
Ein \(\texttt{RuntimeError}\) (auch Laufzeitfehler) tritt auf, wenn ein Programm syntaktisch korrekt ist, aber während der Ausführung einen Fehler verursacht. Diese Art von Fehler verhindert, dass das Programm weiterläuft oder manchmal auch, dass das Programm durchläuft, aber nicht das tut, was Sie wollen.
Ein häufiger Grund für \(\texttt{RuntimeError}\) ist die Verwendung einer nicht definierten bzw. falsch geschriebenen Variablen. Das passiert, wenn man versucht, auf eine Variable zuzugreifen, die vorher nicht deklariert wurde. Dieser Fall hat den Vorteil, dass Python eine Fehlermeldung hervorruft.
Masse = 10
Geschwindigkeit = 5
kinetische_Energie = 0.5 * masse * Geschwindigkeit
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[2], line 3
1 Masse = 10
2 Geschwindigkeit = 5
----> 3 kinetische_Energie = 0.5 * masse * Geschwindigkeit
NameError: name 'masse' is not defined
Hier wurde die Variable \(\texttt{Masse}\) genannt, allerdings in der Rechnug über \(\texttt{masse}\) versucht aufgerufen zu werden. Auch wenn intuitiv klar ist, dass damit die gleiche Größe gemeint ist, kann Python damit nicht umgehen und wirft daher eine Fehlermeldung und spzifiziert den \(\texttt{RuntimeError}\) konkreter als \(\texttt{NameError}\).
Kniffliger wird es, wenn sich im eigenen Code \(\texttt{RuntimeErrors}\) eingeschlichen haben, die keine Fehlermeldung verursachen, aber die Ausführung so beeinflussen, dass das Ergebnis nicht das Gewünschte ist. Im folgenden Code zur Berechnung der \(n\)-ten Fibonacci-Zahl hat sich ein solcher Fehler eingeschlichen. Die Fibonacci-Folge habe Sie bereits im Kontext der for-Schleifen kennengelernt. Wir erinnern nocheinmal an die rekursive Definition:
Aufgabe 2.1
Der Code wirft den Fehler \(\texttt{IndexError}\). Woran könnte das liegen? Passen Sie den Code so an, dass die Fehlermeldung nicht mehr erscheint.
import numpy as np
n = 10
fib = np.zeros(n) # Erstellt ein Array mit 10 Einträgen
fib[0:2] = [0, 1] # Setzt fib[0] = 0 und fib[1] = 1
for k in range(1, n - 1):
fib[k + 1] =fib[k - 1] + fib[k - 2]
fibN = fib[n] # Zugriff auf die zuletzt berechnete Zahl
print(f"Die {n}. Fibonacci-Zahl ist: {fibN}")
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
Cell In[7], line 12
7 for k in range(1, n - 1):
8 fib[k + 1] = (
9 fib[k - 1] + fib[k - 2]
10 ) # Berechnet die Fibonacci-Zahlen iterativ
---> 12 fibN = fib[n] # Zugriff auf die zuletzt berechnete Zahl
13 print(f"Die {n}. Fibonacci-Zahl ist: {fibN}")
IndexError: index 10 is out of bounds for axis 0 with size 10
Hinweis
Der wie vielte Eintrag von \(\texttt{fib}\) wird über \(\texttt{fib[n]}\) abgefragt?
Lösung
import numpy as np
n = 10
fib = np.zeros(n)
fib[0:2] = [0, 1]
for k in range(1, n - 1):
fib[k + 1] = fib[k - 1] + fib[k - 2]
fibN = fib[n - 1] # Korrektur
print(f"Die {n}. Fibonacci-Zahl ist: {fibN}")
Wenn Sie den Code aus der Lösung ausführen, merken Sie dass nun keine Fehlermeldung mehr erscheint. Allerdings ist nach dem Code die \(10.\) Fibonacci-Zahl die Zahl \(4\), was nicht korrekt ist. Die \(10.\) Fibonacci-Zahl ist nämlich \(34\). Solche Fehler erkennt Python leider nicht und Sie müssen Sie selbst durch das Testen Ihres Codes finden.
Aufgabe 2.2
Passen Sie den Code an, sodass die \(10.\) Fibonacci-Zahl korrekt berechnet wird.
# Ihr Code
Hinweis 1
Es kann nützlich sein auch andere Variablen wie \(\texttt{fib}\) zu betrachten, um herauszufinden, an welcher Stelle der Code einen Fehler macht.
Hinweis 2
Läuft die Schleife über die richtigen Elemente? Wird die richtige Zahl überschrieben in der Schleife?
Lösung
import numpy as np
n = 10
fib = np.zeros(n)
fib[0:2] = [0, 1]
for k in range(2, n): # Korrektur
fib[k] = fib[k - 1] + fib[k - 2] # Korrektur
fibN = fib[n - 1] # Korrektur aus A2.1
print(f"Die {n}. Fibonacci-Zahl ist: {fibN}")
Abschließend wollen wir die Anzahl an Mensaessen, die an einer fiktiven Mensa pro Semester komsumiert werden grafisch darstellen und haben den folgenden Code geschrieben. Leider haben sich Fehler eingeschlichen. Der Code erzeugt zunächst die Daten für 30 verschiedene Semester und soll anschließend der Plot erstellen.
Aufgabe 2.3
Finden Sie die Fehler in dem Codeausschnitt und verbessern Sie diese.
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(42) # für reproduzierbare Ergebnisse
# Erzeugung der Anzahl an verkauften Mensaessen pro Semester
trend = 850 + 20 * np.arange(1, 31)
noise = np.random.normal(loc=0, scale=20, size=np.arange(1, 31).shape)
Mensaessen = trend + noise
# Plotten der gemessenen Daten ohne Regression
Semester = np.arange(1, 30)
plt.scatter(Semester, Mensaessen)
plt.xlabel("Mensaessen")
plt.ylabel("Semester")
plt.title("Anzahl der verkauften Mensaessen über die letzten 30 Semester")
plt.show()
Hinweis
Stimme die Dimensionen der zu plottenden Daten überein?
Lösung
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(42)
trend = 850 + 20 * np.arange(1, 31)
noise = np.random.normal(loc=0, scale=20, size=np.arange(1,31).shape)
Mensaessen = trend + noise
Semester = np.arange(1, 31) # Korrektur
plt.scatter(Semester, Mensaessen)
plt.xlabel('Semester')
plt.ylabel('Mensaessen')
plt.title('Anzahl der verkauften Mensaessen über die letzten 30 Semester')
plt.show()
Nun möchten wir eine lineare Regressionsgerade erzeugen. Dazu normieren wir die Daten zunächst und führen dann die Regression durch, indem wir die Funktion \(\texttt{np.polyfit}\) verwenden. Leider haben sich auch hier Fehler eingeschlichen.
Aufgabe 2.4
Finden Sie die Fehler in dem Codeausschnitt und verbessern Sie diese.
# Normalisiere die Daten
Mensaessen_norm = np.max(Mensaessen) / Mensaessen
# Durchführung der Regression
Grad = 1
Koeff = np.polyfit(Semester, Mensaessen_norm, Grad)
polynomial = np.poly1d(Koeff)
Regression_Mensaessen = polynomial(Semester)
plt.scatter(Semester, Mensaessen_norm)
plt.plot(Semester, Regression_Mensaessen, color="r")
plt.xlabel("Semester")
plt.ylabel("Mensaessen")
plt.title("Regression der verkauften Mensaessen über die letzten 30 Semester")
plt.show()
Hinweis
Werden die Daten korrekt normiert?
Lösung
Mensaessen_norm = Mensaessen / np.max(Mensaessen) # Korrektur
Grad = 1
Koeff = np.polyfit(Semester, Mensaessen_norm, Grad)
polynomial = np.poly1d(Koeff)
Regression_Mensaessen = polynomial(Semester)
plt.scatter(Semester, Mensaessen_norm)
plt.plot(Semester, Regression_Mensaessen, color='r')
plt.xlabel('Semester')
plt.ylabel('Mensaessen')
plt.title('Regression der verkauften Mensaessen über die letzten 30 Semester')
plt.show()