Seite 1 von 2
Verständnis Frage (if-else) oder (try-except)
Verfasst: Samstag 11. Oktober 2008, 12:46
von busfahrer
Hallo
Folgendes Szenario
Ich habe ein Dictionary mit folgenden Schlüssel/Wert Paaren(Dienstnummer:Stunden)
eine liste mit folgendem Inhalt(Dienstnummern)
und eine Variable S für Stunden die anfangs auf 0 steht
Nun sieht mein Code so aus:
Code: Alles auswählen
for i in l:
if i in d:
s += d[i]
else:
print "Dienstnummer: %s existiert nicht"% i
Wo liegt der Unterschied hierzu
Code: Alles auswählen
try:
for i in l:
s += d[i]
except Keyerror:
print "Dienstnummer: %s existiert nicht"% i
im Bezug auf die Fehlerbehandlung.
Das Ergebnis im Programm ist für mich(auf den ersten Blick)
das selbe.
Hoffe auf Erleuchtung
Gruß....busfahrer
Verfasst: Samstag 11. Oktober 2008, 12:56
von Darii
Ersetze
l durch
und lass dein Programm damit mal laufen, evtl. kommst du ja so dahinter was da anders ist.
btw: Außerdem hast du da noch einen Einrückungsfehler, das was du da hast ist ein for-else und kein if-else. Die
Doku sollte dir da weiterhelfen.
Verfasst: Samstag 11. Oktober 2008, 13:01
von roschi
hallo!
wenn ein key in einem dictionary nicht existiert, wird ein 'KeyError' ausgeloest.
beispiel:
Code: Alles auswählen
>>> d = {"a":10, "b":80, "c":1}
>>> d["a"]
10
>>> d["x"]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'x'
achja, und so muss dein code aussehen:
Code: Alles auswählen
for i in l:
if i in d:
s += d[i]
else:
print "Dienstnummer: %s existiert nicht"% i
oder, mit fehlerbehandlung:
Code: Alles auswählen
try:
for i in l:
s += d[i]
except Keyerror:
print "Dienstnummer %s existiert nicht" % i
mfg
roschi
Verfasst: Samstag 11. Oktober 2008, 13:20
von busfahrer
Hi
btw: Außerdem hast du da noch einen Einrückungsfehler, das was du da hast ist ein for-else und kein if-else. Die Doku sollte dir da weiterhelfen.
Hab den Fehler nur hier beim Posten ins Forum gemacht.Im Programm
ist alles richtig eingerückt.
Habe festgestellt das bei der Variante mit if-else der Fehler ausgegeben wird,aber es wird über die komplette Liste durch iteriert.
Bei der Variante mit try-except wird der Fehler ausgegeben und die Iteration über die Liste an der Stelle abgebrochen.
Somit sollte Variante 2 speicherschonender sein.
Liege ich da mit meiner Annahme richtig?
Gruß....busfahrer
Verfasst: Samstag 11. Oktober 2008, 13:43
von roschi
hallo busfahrer!
du musst doch wissen, was du willst.
wenn er bei einem nicht-vorhandenen key abbrechen soll, nimm die variante mit try/except.
wenn er weitermachen soll, dann nimm die mit if/else.
es ist nicht wirklich speicherschonender. dein float 's' wird dann eben nur groeßer ^^ aber das soll es ja - du willst doch alle stunden zusammenziehen.
mfg
roschi
Verfasst: Samstag 11. Oktober 2008, 13:44
von snafu
"i" finde ich an dieser Stelle sehr verwirrend, da man einen Zähler erwartet (z.B. den Index). Passender wäre wohl "elem". Oder gleich so:
Code: Alles auswählen
import sys
book_of_hours = {"1001":7.8,"1002":5.4,"1003":6.5}
id_numbers = ["1001","1002","1004"]
for id_nr in id_numbers:
try:
hours += book_of_hours[id_nr]
except KeyError:
print >> sys.stderr, id_nr, "does not exist"
Verfasst: Samstag 11. Oktober 2008, 13:47
von cofi
Wenn dir die Dienstnummern egal sind kannst du auch mit
arbeiten.
Unabhängig davon: Mach dir das Leben einfacher und benutze sprechende Namen.
Verfasst: Samstag 11. Oktober 2008, 14:10
von busfahrer
@roschi
du musst doch wissen, was du willst.
Natürlich weiss ich was ich will.Mir hatte sich nur zuerst der
Unterschied zwischen beiden Varianten nicht erschlossen.
Bin nun Dank euch wieder etwas schlauer
Da ich die Dienstnummer im Textfenster eh von falsch in
richtig ändern muß und beim erneuten Berechnen über
die komlette Liste neu iteriert wird,werde ich mich für
Variante 2(try-except) entscheiden.
@snafu
vielen Dank für deinen Verbesserungsvorschlag
Gruß....busfahrer
Verfasst: Samstag 11. Oktober 2008, 14:35
von snafu
Deine try-except-Variante umschliesst übrigens den kompletten Versuch. Das heißt: Sobald ein KeyError geworfen wird, bricht er ab und zeigt deine Fehlermeldung an. Bei meiner Variante wird der try-except-Block für jedes Element aus der Dienstnummernliste ausgeführt, was bedeutet, dass alle nicht existierenden Nummern gemeldet werden und halt auch alle Nummern, die existieren, zu den Gesamtstunden addiert werden (unabhängig von möglichen KeyErrors).
Verfasst: Samstag 11. Oktober 2008, 17:45
von busfahrer
@snafu
Bei meiner Variante wird der try-except-Block für jedes Element aus der Dienstnummernliste ausgeführt, was bedeutet, dass alle nicht existierenden Nummern gemeldet werden
Habe die GUI für mein Prog mit Tkinter bzw. Tix geschrieben.
Schaffe es aber leider nicht,deine Variante in einem Textfenster
auszugeben.Könntest du mir vielleicht noch einen dezenten
Hinweis geben ob das überhaupt geht.Wenn ja wäre ich schon froh,
wenn du mich in die richtige Richtung schubsen würdest
Gruß....busfahrer
Verfasst: Samstag 11. Oktober 2008, 18:00
von cofi
snafu schreibt in StandardError.
Da muss aber nicht ran. Du kannst stattdessen ein Label in dein GUI aufnehmen und dessen Text in der except-Suite auf
ändern.
Vielleicht solltest du noch ein paar Worte dazu verlieren wie das ganze denn ablaufen soll, dann kann man dir auch besser helfen

Verfasst: Samstag 11. Oktober 2008, 18:38
von busfahrer
Hallo
also hier mal das relevante Stück Code
Code: Alles auswählen
def ergebnis(self):
self.erg_dz_entry.delete(0, tx.END)
self.erg_sm_entry.delete(0, tx.END)
self.std_kto_entry.delete(0, tx.END)
self.ges_std = 0.0
self.std_kto = 0.0
self.dienstplan = open("/home/thomas/skripte/dienstplan.bin", "rb")
self.dienste = pickle.load(self.dienstplan)
self.dienstplan.close()
self.dienstnummern = self.fenster.get(1.0, tx.END)
self.dienstnummern = self.dienstnummern.strip().split(",")
try:
for dienst in self.dienstnummern:
self.ges_std += self.dienste[dienst]
self.std_kto += self.dienste[dienst] - 7.8666666667
except KeyError:
self.fenster.insert(tx.END, "\nDienstnr.:%s existiert nicht"% dienst)
Jetzt ist es ja im Moment so das bei der Exception nur die erste
falsche Dienstnummer ausgegeben wird,egal wieviele es tatsächlich
sind.Ich hätte aber gerne,wenn möglich,das alle falschen
Dienstnummern ausgegeben werden.
Hoffe das Codesnippet hilft.
Gruß....busfahrer
Verfasst: Samstag 11. Oktober 2008, 19:07
von cofi
Das ist ganz klar, dass das nur die erste falsche Dienstnummer ist

Darauf haben dich snafu und roschi aber auch hingewiesen.
Code: Alles auswählen
if key not in d.keys():
errorlist.append(key)
else:
print d[key]
Verfasst: Samstag 11. Oktober 2008, 21:11
von busfahrer
Habs nun zu meiner Zufriedenheit hin bekommen
Vielen Dank noch mal an alle
Gruß....busfahrer
Verfasst: Samstag 11. Oktober 2008, 21:15
von birkenfeld
Verfasst: Samstag 11. Oktober 2008, 22:47
von Fabian Kochem
birkenfeld: Das ist doch das Selbe?
Verfasst: Samstag 11. Oktober 2008, 23:07
von Trundle
Die `has_key`-Methode von dicts wird mit Py3k verschwinden. Außerdem ist ``key in d`` doch viel schicker.
Verfasst: Sonntag 12. Oktober 2008, 10:04
von birkenfeld
``key in d`` und ``d.has_key(key)`` tut das gleiche, und wie Trundle sagt, ist ersteres vorzuziehen.
``key in d.keys()`` allerdings ist doppelt falsch: es wird extra eine neue Liste aller Keys erzeugt *und* diese muss dann in linearer Zeit nach "key" durchsucht werden, während eine Suche direkt im Dictionary auf O(1) hinausläuft.
Verfasst: Sonntag 12. Oktober 2008, 10:39
von BlackJack
@busfahrer: Du bindest in dem gezeigten Quelltextschnippsel zu viel an das Objekt. `dienstplan`,`dienste` und `dienstnummern` zum Beispiel.
Ist es ein Problem, dass wenn man eine Dienstnummer mehrfach angibt, die auch mehrfach aussummiert wird? Vielleicht solltest Du die Benutzereingabe einfach mal komplett vor der Aufsummierung prüfen und gar nicht erst rechnen, wenn da Fehler enthalten sind.
Vorausgesetzt alle Nummer in `dienstnummer` sind gültig, kann man die Berechnung auch so machen:
Code: Alles auswählen
def ergebnis(self):
# ...
gesellschafts_standard = sum(dienste[n] for n in dienstnummern)
standard_konto = gesellschafts_standard - (len(dienstnummern) * 7.8666666667)
# ...
Wobei solche magischen Zahlen wie 7.8666666667 oder hart kodierte Pfadangaben kein guter Stil sind. So etwas gehört als Konstante definiert und ggf. erklärt.
Verfasst: Sonntag 12. Oktober 2008, 10:42
von numerix
@birkenfeld:
In der Doku zu 2.5 hieß es:
a.has_key(k) Equivalent to k in a, use that form in new code
Das habe ich so verstanden, dass die Variante a.has_key(k) diejenige sei, die man verwenden solle.
In der Doku zu 2.6 heißt es nun:
dict.has_key(key) is equivalent to key in d, but deprecated.
Das lese ich nun aber so, dass man die Methode has_key() gerade NICHT mehr verwenden sollte.
Habe ich die Fassung "2.5." einfach falsch gelesen oder hat sich da tatsächlich ein Sichtwechsel ereignet?