Verständnis Frage (if-else) oder (try-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.
busfahrer
User
Beiträge: 111
Registriert: Donnerstag 9. Oktober 2008, 17:42

Hallo
Folgendes Szenario
Ich habe ein Dictionary mit folgenden Schlüssel/Wert Paaren(Dienstnummer:Stunden)

Code: Alles auswählen

d = {"1001":7.8,"1002":5.4,"1003":6.5}
eine liste mit folgendem Inhalt(Dienstnummern)

Code: Alles auswählen

l = ["1001","1002","1004"]
und eine Variable S für Stunden die anfangs auf 0 steht

Code: Alles auswählen

s = 0.0
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
Alles wird gut ;-)
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

Ersetze l durch

Code: Alles auswählen

l = ["1001","1002","1004","1005"]
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.
Benutzeravatar
roschi
User
Beiträge: 225
Registriert: Samstag 29. März 2008, 18:58
Wohnort: Thueringen, Deutschland
Kontaktdaten:

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
[size=117]Fuer Alle, die in Python einsteigen wollen, kann ich das Buch [url=http://abop-german.berlios.de/]A Byte of Python[/url] nur waermstens empfehlen![/size]
busfahrer
User
Beiträge: 111
Registriert: Donnerstag 9. Oktober 2008, 17:42

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
Alles wird gut ;-)
Benutzeravatar
roschi
User
Beiträge: 225
Registriert: Samstag 29. März 2008, 18:58
Wohnort: Thueringen, Deutschland
Kontaktdaten:

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
[size=117]Fuer Alle, die in Python einsteigen wollen, kann ich das Buch [url=http://abop-german.berlios.de/]A Byte of Python[/url] nur waermstens empfehlen![/size]
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

"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"
Zuletzt geändert von snafu am Samstag 11. Oktober 2008, 13:50, insgesamt 2-mal geändert.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Wenn dir die Dienstnummern egal sind kannst du auch mit

Code: Alles auswählen

for hour in d.itervalues():
    s += hour
arbeiten.

Unabhängig davon: Mach dir das Leben einfacher und benutze sprechende Namen.
busfahrer
User
Beiträge: 111
Registriert: Donnerstag 9. Oktober 2008, 17:42

@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
Alles wird gut ;-)
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

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).
busfahrer
User
Beiträge: 111
Registriert: Donnerstag 9. Oktober 2008, 17:42

@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
Alles wird gut ;-)
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

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

Code: Alles auswählen

"%s does not exist" % id_nr
ändern.

Vielleicht solltest du noch ein paar Worte dazu verlieren wie das ganze denn ablaufen soll, dann kann man dir auch besser helfen ;)
busfahrer
User
Beiträge: 111
Registriert: Donnerstag 9. Oktober 2008, 17:42

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
Alles wird gut ;-)
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

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]
busfahrer
User
Beiträge: 111
Registriert: Donnerstag 9. Oktober 2008, 17:42

Habs nun zu meiner Zufriedenheit hin bekommen :D

Vielen Dank noch mal an alle

Gruß....busfahrer
Alles wird gut ;-)
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

cofi hat geschrieben:

Code: Alles auswählen

if key not in d.keys():
Das heißt

Code: Alles auswählen

if key not in d:
.
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
Fabian Kochem
User
Beiträge: 36
Registriert: Mittwoch 5. April 2006, 14:11
Wohnort: Köln

birkenfeld: Das ist doch das Selbe?

Code: Alles auswählen

if dictionary.has_key(key):
    ...
Benutzeravatar
Trundle
User
Beiträge: 591
Registriert: Dienstag 3. Juli 2007, 16:45

Die `has_key`-Methode von dicts wird mit Py3k verschwinden. Außerdem ist ``key in d`` doch viel schicker.
"Der Dumme erwartet viel. Der Denkende sagt wenig." ("Herr Keuner" -- Bertolt Brecht)
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

``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.
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
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.
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

@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?
Antworten