wo im script setzt man genau try und except

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
78gradn
User
Beiträge: 18
Registriert: Dienstag 13. Oktober 2015, 21:15

Hallo

ich habe ein kurzes script erstellt und sollte mittels try...except eventuelle Fehler abfangen (Vorgabe der Übungsleitung).
Vermutlich eine ganz banale Frage, kann die Antwort darauf dennoch nicht finden:
Wie und Wo genau setz ich das try: und das except:?
Hier mein Script:

Code: Alles auswählen

import math

a = math.pi/180*15
b = math.pi/180*20.4

c = raw_input("c")
d = raw_input ("d")

e = float(c)
f = float(d)

g= 6370 * math.acos(math.sin(a) * math.sin(f) + math.cos(a) * math.cos(f) * math.cos(b-f))
try:
 print g
except:
        print "nei"

raw_input("Press return to close this window...")
Wenn ich das try und except so wie eben dargestellt setzt, funktionert es zwar; aber ich frage mich ob das Sinn macht - es überprüft ja in diesem Fall nur ob ich g richtig geschrieben habe (was bei g zugegebener Massen machbar zu sein scheint).

Also, würde es nicht mehr sinn machen, das ganze statement zu überprüfen? Wenn ich try aber weiter oben setzte, bekomm ich als Rückmeldung immer " syntax error - expected an indented block".

Wäre froh um rasche Hilfe - Vielen Dank vorab...

Marla (volle Anfängerin )
Zuletzt geändert von Anonymous am Samstag 17. Oktober 2015, 00:37, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Code-Tags gesetzt.
Benutzeravatar
Kebap
User
Beiträge: 687
Registriert: Dienstag 15. November 2011, 14:20
Wohnort: Dortmund

Hallo und willkommen bei Python und im Forum.

Man setzt try und except immer vor und nach einem (möglichst kleinen) Scriptteil, in dem eventuell etwas schief gehen könnte.

Das ist print meist nicht.

Was beispielsweise schief gehen könnte: Division durch Null.

Üblicherweise schreibt man auch nicht einfach ein blankes except, sondern gibt genau an, welche Fehler man abfangen will. Dazu sollte auch was in deinen Unterlagen stehen?

Du beschreibst noch eine andere Fehlermeldung, die hat aber nichts mit try/except zu tun, sondern vermutlich damit, dass du eine Zeile nicht richtig eingerückt hattest. Das ist bei Python essentiell, um Blöcke im Script voneinander zu trennen. Man benutzt meist einheitlich 4 Leerzeichen, nicht einmal 1 dann 8. Dies erleichtert die Lesbarkeit ungemein. Ebenso wie sinnvolle Namen der Variablen, nicht einfach a bis g. Am besten zeigst du mal das veränderte Script und die komplette Fehlermeldung, falls du noch Hilfe brauchst.

Bzgl. der letzten Zeile in deinem Skript: Wie startest du dein Python? Sowas sollte eigentlich unnötig sein...
MorgenGrauen: 1 Welt, 8 Rassen, 13 Gilden, >250 Abenteuer, >5000 Waffen & Rüstungen,
>7000 NPC, >16000 Räume, >200 freiwillige Programmierer, nur Text, viel Spaß, seit 1992.
BlackJack

@78gradn: Zwischen ``try`` und ``except`` muss ein eingerückter Code-Block stehen, deswegen bekommst Du die Ausnahme.

Man setzt ``try``/``except`` um die Anweisung(en) bei denen man einen oder mehrere *konkrete* Ausnahmen erwartet und die man *sinvoll* *behandeln* kann. Also zwischen ``except`` und dem ``:`` sollte eigentlich immer etwas stehen, ein ”nacktes” ``except:`` wie in Deinem Beispiel ist fast immer falsch. Das macht man eigentlich nur wenn man in der Behandlung dann entweder die Ausnahme erneut auslöst oder komplett, inklusive Traceback protokolliert, damit man eine Chance hat unerwartetes zu entdecken und herauszufinden welche Ausnahmen da ”unterdrückt” wurden. Ansonsten kann die Fehlersuche schwierig bis unmöglich werden.

Der ``try`-Block sollte auch möglichst kurz sein, damit man möglichst nur eine Quelle für die Ausnahme hat die man im ``except``-Block behandelt. So etwas wie ein `ValueError` kann bei vielen Operationen passieren, auch in Funktionen die man aufruft, oder Funktionen die von den Funktionen aufgerufen werden die man selber aufruft. Und wenn man zig Codezeilen im ``try``-Block stehen hat und im ``except ValueError:`` dann alle Möglichkeiten wie in diesen Zeilen ein `ValueError` auftreten kann, gleich behandelt, dann ist das sehr wahrscheinlich keine angemessene Ausnahmebehandlung. Wenn man auf kurze ``try``-Blöcke achtet, sollte man nicht vergessen das zu einem ``try``/``except`` auch ein ``else``-Block gehören kann! Nämlich für den Fall das *keine* Ausnahme im ``try``-Block aufgetreten ist.

Ein einfaches ``print 'Fehler!'`` ist übrigens in aller Regel auch keine sinnvolle Fehlerbehandlung. Das nutzt weder dem Benutzer noch dem Programmierer herauszufinden was denn der Fehler eigentlich war. Ist das einer im Programm? Oder einer der durch falsche Eingaben vom Benutzer entstanden ist? Was ist/war die Ursache? Das muss man ja sowohl als Benutzer als auch als Programmierer wissen um das Problem zu korrigieren. Und da ist eine Ausnahme die unbehandelt zum Programmabbruch führt und eine Nachricht ausgibt *und* einen Traceback der Rückschlüsse auf den Programmablauf zulässt, der zu der Ausnahme geführt hat, nützlicher als ein nichtssagendes 'Fehler!'. Oder 'nei' — das ist nicht besser. :-)

Die Frage ist also wo und welche Ausnahme(n) Du erwartest. Beim ``print g`` offenbar keine, und das wohl auch zurecht, denn das meiste was dabei schief gehen kann, ist an der Stelle sowieso nicht sinnvoll behandelbar. Du musst also schauen wo Du Ausnahmen bekommen kannst und wie man die dann behandeln kann. Gibt es irgendwo Operationen oder Funktionsaufrufe bei denen Werte involviert sein können für die diese Operationen oder Funktionen nicht sinnvoll angewendet werden können und deshalb Ausnahmen ausgelöst werden?

Anmerkungen zum Code: Gib den Werten vernünftige Namen die dem Leser vermitteln was der Wert bedeutet. Einbuchstabige Namen dem Alphabet nach sind das eher nicht. Und man muss auch nicht jedes kleine Zwischenergebnis an einen Namen binden wenn man das nicht mehr als einmal benötigt, vor allem nicht wenn der Name auch noch nichtssagend ist.

Für `a` und `b` könnte man auch `math.radians()` verwenden, dann weiss man als Leser schneller was diese Rechnung soll, beziehungsweise kann in der Dokumentation die Funktion nachlesen und weiss es dann.
78gradn
User
Beiträge: 18
Registriert: Dienstag 13. Oktober 2015, 21:15

vielen Dank an beide für die rasche Antwort :D
Da hab ich ja noch einiges zu tun ...

Verm. geht es hier nur darum zu sehen ob ich try und except verstanden hab. - hab ich bisher leider nicht wirklich.
Vielen Dank auf jeden Fall für die Tips. Das mit dem Einrücken hab ich nicht beachtet.

Also versteh ich das richtig: es ist nicht üblich das ganze Script auf einmal auf Fehler zu überprüfen sondern nur gezielt einen kleinen Teil?
Wenn ich mehrere kleine Teile mit potentieller Fehleranfälligkeit habe, mach ich dann das Try... except öfter in einem Durchgang oder jeweils nur einmal?

Welche Zeilen müssen denn eingerückt werden? Immer die erste in einem neuen Block oder alle?

Vielen Dank nochmal... bin extrem froh über die Hilfe hier
78gradn
User
Beiträge: 18
Registriert: Dienstag 13. Oktober 2015, 21:15

ich bin noch nicht soweit alle tips umzusetzten (ordentliche Variablen etc), aber dennoch hab ich noch zwei konkrete Fragen:
Ich habs jetzt durch das richtige Einrücken geschaft ein try except statement zu setzen.

siehe da:

Code: Alles auswählen

import math
a = math.pi/180*15
b = math.pi/180*20.4
c = raw_input("c")
d = raw_input ("d")

e = float(c)
f = float(d)

try:
     g = 6370 * math.acos(math.sin(a) * math.sin(a) + math.cos(a) * math.cos(f) * math.cos(b-f))

except (ValueError):
    print ("Fehler in Berechnungsformel")

print g

raw_input("Press return to close this window...")
1. gibt es eine Liste mit Bezeichnungen möglicher Fehler (also wie eben ValueError) oder kann man da willkürlich formulieren?

2. wenn ich mein Script so laufen lasse, bekomm ich ein Ergebnis. Alles gut.
Mich würde interessieren was ich anders schreiben müsste damit mir "Fehler in Berechnungsformel" - also der except Fall im Ausgabefenster angezeigt wird.
Wenn ich in der Formel was verändere dann bekomm ich ja vorher schon eine Fehlermeldung (syntax error) oder (hier zum beispiel hab ich absichtlich einen float durch einen string ersetzt)sowas:

Code: Alles auswählen

line 13, in <module>
    g = 6370 * math.acos(math.sin(a) * math.sin("a") + math.cos(a) * math.cos(f) * math.cos(b-f))
TypeError: a float is required
Mir ist klar, dass ich einen float brauche - war jetzt eben zum Test. Ich hatte mir erhofft, dass ich dann eben die Exceptmeldung bekomme.
Was versteh ich denn da falsch?
Nochmals vielen Dank
Zuletzt geändert von Anonymous am Samstag 17. Oktober 2015, 04:50, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Code-Tags gesetzt.
78gradn
User
Beiträge: 18
Registriert: Dienstag 13. Oktober 2015, 21:15

Kebap hat geschrieben:
Bzgl. der letzten Zeile in deinem Skript: Wie startest du dein Python? Sowas sollte eigentlich unnötig sein...
Momentan übe ich gemäss übungsvorgabe in Pythonwin. Dort geb ich ins scriptfenster ein und im Ausgabefenster kommt das ergebnis nachdem ich run aktiviert habe.
In der Übungsaufgabe werde ich aber angwiesen, dass aas Script auch außerhalb des verwendeten Python Editors per
Doppelklick ausführbar sein sollte...

Was das heisst, weiss ich offengestanden bis jetzt auch noch nicht wirklich.
Hintergrund:
Ich bin ja Geographin und Python muss ich mir nun aneignen um in Geoinformationssoftware Tools oder Modelle erstellen zu können.
So bin ich halb unverhofft zum Programmieren lernen gekommen mit relativ wenig Verständnis für Informatik generell :| :|

Vielen Dank noch mal und hg
__deets__
User
Beiträge: 14542
Registriert: Mittwoch 14. Oktober 2015, 14:29

Hallo Marla,

also zuersteinmal zur Aufmunterung: du schlägst dich nicht schlecht. Du gehst systematisch vor, und stellst gute Fragen. Summa summarum: das wird schon, mit dir und dem Programmieren.

Konkret zu deinen Problemen:
  • bitte setze Code in die dazugehoerigen Tags, die du hier oben im Editor siehst. Gerade bei Python ist Einrueckung wichtig, und ohne die Code-Tags verschwindet die.
  • du bist ja in ArcGIS unterwegs, wie wir schon mal in einem anderen Thread festgestellt haben. Das ist per se nicht schlecht, hat aber bei diesen grundsaetzlichen Fragen einen grossen Nachteil: manche der Dinge, die gehen oder nicht, haben mit dieser doch speziellen und von den wenigsten hier besessenen Umgebung zu tun. Auch wenn es schwerfaellt: loes dich davon fuer den Moment. Pythonwin mag funktioniernen, Notepad++ tut es auch, oder wie schon erwaehnt Sublime, und ausser Word wahrscheinlich noch so manches mehr. Aber wichtiger ist: schreibe ein Programm in einem Editor, aber fuehre es aus auf der Kommandozeile. Das nervt ein bisschen, aber dort ist die natuerliche Umgebung einer Programmiersprache. Da gibt's seitenlange Fehlerausgaben, und man muss nix doppelklicken & hoffen, dass es klappt. Denn wenn es das nicht tut, gibt's bei Doppelklick nur ein kurz aufblitzendes Fenster, und das war's. Dann braucht man auch die letzte Zeile nicht, die auch nur nuetzt, wenn sie erreicht wird - bricht das Programm vorher ab, schliesst sich das Fenster sofort.
  • der Exceptions sind in Python viele. Und leider gibt es dafuer keinen zentralen Sammelplatz, in dem man sie alle findet. Fuer eingebaute Funktionalitaet wie Datei Ein/Ausgabe und Co ist es ueblicherweise dokumentiert - und teilweise nicht. Das ist doof, aber nicht zu aendern, hier und jetzt. Aber grundsaetzlich geht es ja erstmal darum zu verstehen, wie sie funktionieren, und dazu greife ich mal jetzt auf einen Klassiker zurueck:

Code: Alles auswählen

d = { "a" : 100, "b" : 100}
try:
   d["c"] * 1000
except KeyError, e:
   print e
Exceptions (oder auch Ausnahmen) treten dann auf, wenn etwas passiert, das so nicht vorgesehen war. In meinem simplen Beispiel greife ich auf ein Woerterbuch, das Schluessel auf Werte abbildet ("a" zeigt auf 100, etc), mit einem Schluessel zu, der nicht existiert. Das provoziert einen KeyError. Den kann man auf die gezeigte Art und Weise abfangen.

Es gibt viele andere, deine Problembeschreibung ist da vage - aber zB teilen durch Null ist eine andere (ZeroDivisionError). Auch ein Klassiker: IndexError, beim Zugriff auf nicht-existente Listenelemente:

Code: Alles auswählen

l = [1, 2, 3]
l[5] # Indizes in l reichen nur von 0-2 - alles andere liefert IndexError
Und in deinem Beispiel - naja. Du lieferst halt einen String, und nicht eine Gleitkommazahl -also TypeError - falscher Datentyp. Dagegen wuerde man einen ValueError bekommen, wenn man zwar den Typ getroffen hat, aber der konkrete Wert nicht stimmt. Beispiel:

Code: Alles auswählen

v = int("abcde")
int nimmt zwar einen String/Zeichenkette - aber er ist nicht wandelbar in eine Zahl, darum ist es kein TypeError, aber ein ValueError
BlackJack

@78gradn: Bei der Berechnungsformel sehe ich keine offensichtliche Ausnahme lauern sofern man die nicht mutwillig ”zerstört”. Eine Division durch 0 kann nicht vorkommen und die verwendeten Funkionen sollten eigentlich mit jeder Gleitkommazahl bis auf *zwei* Ausnahmen klarkommen. Ich weiss nicht ob der Dozent *die* überhaupt auf dem Schirm hat, ich denke eher nicht und die Formel/Berechnung ist nicht die Stelle wo Ausnahmen behandelt werden sollen. Wobei das sicher keinen schlechten Eindruck macht wenn Du die Ausnahme(n) herausfindest und berücksichtigst. :-)

Die offensichtlichere Stelle wo es Probleme geben kann ist immer wenn Werte in ein Programm kommen über die Du keine Kontrolle hast. Benutzer von Programmen machen manchmal komische Sachen und Eingabedateien enthalten nicht immmer das was man erwartet. Ein robustes Programm reagiert auch auf Falscheingaben von Benutzern oder Dateien mindestens mit einem geordneten Ende statt dem Benutzer eine Ausnahme zu präsentieren. Bei einer Eingabe wie in diesem Fall wäre es sogar schön wenn das Programm nicht abbricht, sondern den Benutzer solange nach einer Eingabe fragt bis der etwas sinnvolles/passendes eingegeben hat.
78gradn
User
Beiträge: 18
Registriert: Dienstag 13. Oktober 2015, 21:15

hey, vielen dank für die vielen tips. jetzt ist vieles verständlicher.
mach mich gleich an die arbeit!!!
danke und hg
78gradn
User
Beiträge: 18
Registriert: Dienstag 13. Oktober 2015, 21:15

Hallo nochmal,

ich hab jetzt versucht Eure Tips weitestgehend umzusetzen. Hoffe das ist mir gelungen.?
Ich hab das try except jetzt dort hin gesetzt wo der Benutzer die Eingabe machen muss (raw_input).
Siehe da:
.............................................................
import math

lat1 = math.pi/180*47.8
lon1 = math.pi/180*13

try:
latitude2 = raw_input("latitude2")
longitude2 = raw_input ("longitude2")


lat2 = float(latitude2)
lon2 = float(longitude2)

except ValueError:
print ("falsche Eingabe")

dist = 6370 * math.acos(math.sin(lat1) * math.sin(lat2) + math.cos(lat1) * math.cos(lat2) * math.cos(lon2 -lon1))


distanz = round(dist,1)
print "Die Distanz betraegt" " " + str(distanz) +" " "Kilometer."

raw_input("Press return to close this window...")
........................................................................................

Wenn ich jetzt als Benutzer absichtlich einen Buchstaben statt einer Zahl eingebe bekomm ich tatsächlich die Rückmeldung "falsche Eingabe". Also das was im Except Fall ausgegeben werden soll. ABER: Er rechnet mir dennoch ein Ergebnis aus. Hat das so seine Richtigkeit? Müsste die Ausgabe dann nicht bei "falsche Eingabe" gestoppt werden?

Danke nochmal und hg
Benutzeravatar
Kebap
User
Beiträge: 687
Registriert: Dienstag 15. November 2011, 14:20
Wohnort: Dortmund

78gradn hat geschrieben:Welche Zeilen müssen denn eingerückt werden? Immer die erste in einem neuen Block oder alle?
Der komplette Block. Du kannst auch Blöcke-in-Blöcken haben. Sobald die Einrückung aufhört, versteht Python, dass der Block vorbei ist.
MorgenGrauen: 1 Welt, 8 Rassen, 13 Gilden, >250 Abenteuer, >5000 Waffen & Rüstungen,
>7000 NPC, >16000 Räume, >200 freiwillige Programmierer, nur Text, viel Spaß, seit 1992.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@78gradn: Da bist Du inzwischen schon gut weiter gekommen und auch die Frage, ob das Programm im Fehlerfall abbrechen sollte, führt in die richtige Richtung. Nämlich die der konditionalen Programmausführung (if then else). Zunächst aber brauchen wir dies noch nicht.
Erst einmal zu Blöcken: Python erwartet nach einem Doppelpunkt einen neuen Block, d.h. eine weitere Ebene der Einrückung:

Code: Alles auswählen

try:
    n = float(raw_input("Längengrad eingeben:"))
except ValueError:
    print "Bitte eine Zahl eingeben."
Dies ist Deine Eingabe und try umfasst nur eine Zeile. Gibt der Nutzer etwas ein, das nicht in eine Fließkommazahl konvertiert werden kann, wird die Fehlermeldung ausgegeben.
Das brauchst Du zweimal, nämlich noch für den Breitengrad. Eine gute Gelegenheit, eine Funktion daraus zu machen:

Code: Alles auswählen

def get_value(text):
    while True:
        try:
            value = float(raw_input(text))
        except ValueError:
            print "Bitte eine Zahl eingeben."
        else:
            return value

Mit 'def' legst Du eine Funktion an. Der Funktionsname ist (fast) frei wählbar und hier 'get_value'. Zudem wird ein Parameter ('text') übergeben, der innerhalb der Funktion verwendet werden kann. Auch die Namen der Parameter sind frei wählbar.
Mit 'while True:' öffnen wir eine Schleife, die durch eine 'return' Anweisung wieder verlassen werden kann, die zugleich auch das Ergebnis der Funktion zurückgibt.
Nun kannst Du diese Funktion zur Eingabe nutzen:

Code: Alles auswählen

longitude = get_value("Bitte Längengrad eingeben:")
latitude = get_value("Bitte Breitengrad eingeben:")
Schleifen und Funktionen sind komplexer, als diese einfache Anwendung hier. Aber wenn Du dieses Beispiel hier verstanden hast, kannst Du Dich leicht weiter einlesen - und findest vielleicht sogar Gefallen am Programmieren :-)
78gradn
User
Beiträge: 18
Registriert: Dienstag 13. Oktober 2015, 21:15

wow, vielen Dank. Ich lern ja in windeseile immer mehr :) !
Und tatsächlich, während ich am Anfang mit erheblichem Respekt an die Sache heran gegangen bin, fängts allmählich an spass zu machen!
Also, vielen Dank an euch Experten!!!
Antworten