Vermeidung verschachtelter try...except Blöcke

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
skirnir
User
Beiträge: 33
Registriert: Sonntag 25. Januar 2015, 10:59

Hallo,

ich versuche gerade, JSON-Objekte, die als Email-Attachments ankommen, zu dekodieren. Diese können in unterschiedlichen Kodierungen ankommen, so dass nicht jeder Versuch von Erfolg gekrönt ist. Derzeit sieht das so aus:

Code: Alles auswählen

try:
    # plain text?
    myvar = json.loads(mystring)
except ValueError:
    # base64?
    try:
        myvar = json.loads(base64.decode(mystring))
    except ValueError:
        try:
            # quoted-printable?
            myvar = json.loads(quopri.decodestring(mystring))
        except ValueError:
            logger.error("None of the above.")
Ist häßlich und kann ggf. zu einer beliebigen Tiefe der Verschachtelung führen, was dann irgendwann unlesbar wird.

Als Alternative fällt mir bisher nur so was ein (ungetestet):

Code: Alles auswählen

def decode_string(source_string, mydecoders=None):
    if mydecoders is None:
        mydecoders = iter((lambda x: x, base64.decode, quopri.decodestring))

    try:
        current_decoder = next(mydecoders)
        return json.loads(current_decoder(source_string))
    except ValueError:
        return decode_string(source_string, mydecoders)
    except StopIteration:
        return None
Das würde zwar nicht zu weiterer Verschachtelung führen, ist aber vielleicht auch nicht intuitiv für jeden zu lesen.

Gibt es eine einfachere (und lesbarere) Möglichkeit, so was auszudrücken?
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

@skirnir: ist in den Email-Anhängen denn kein Encoding angegeben?

Rekursion ist in diesem Fall ein Fehler, weil es kein rekursives Problem ist. Nimm einfach eine for-Schleife:

Code: Alles auswählen

def decode_string(source_string, decoders=(lambda x: x, base64.decode, quopri.decodestring)):
    for decoder in decoders:
        try:
            return json.loads(decoder(source_string))
        except ValueError:
            pass
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

skirnir hat geschrieben:Gibt es eine einfachere (und lesbarere) Möglichkeit, so was auszudrücken?
Klar, das geht.

Code: Alles auswählen

class MyDecoderException(Exception): pass

def decode_string(source, decoders):
    for decoder in decoders:
        try:
            return json.loads(decoder(source))
        except ValueError:
            continue
    raise MyDecoderException('no matching decoder')
skirnir
User
Beiträge: 33
Registriert: Sonntag 25. Januar 2015, 10:59

Sirius3 hat geschrieben:@skirnir: ist in den Email-Anhängen denn kein Encoding angegeben?
Ich arbeite mit einer email.message.Message Instanz. `get_content_type` liefert "application/octet-stream", was ja im Prinzip alles sein kann. Hab' ich evtl. übersehen, wie ich das Encoding rausfinden kann?
Rekursion ist in diesem Fall ein Fehler, weil es kein rekursives Problem ist. Nimm einfach eine for-Schleife:

Code: Alles auswählen

def decode_string(source_string, decoders=(lambda x: x, base64.decode, quopri.decodestring)):
    for decoder in decoders:
        try:
            return json.loads(decoder(source_string))
        except ValueError:
            pass
Ja, das ergibt mehr Sinn. Danke!
skirnir
User
Beiträge: 33
Registriert: Sonntag 25. Januar 2015, 10:59

skirnir hat geschrieben: Ich arbeite mit einer email.message.Message Instanz. `get_content_type` liefert "application/octet-stream", was ja im Prinzip alles sein kann. Hab' ich evtl. übersehen, wie ich das Encoding rausfinden kann?
Falls mal jemand diesen Thread findet:
Das Objekt hat einen key 'Content-Transfer-Encoding', in dem das Encoding drin steht (duh!):

Code: Alles auswählen

mail_part.get('Content-Transfer-Encoding')
BlackJack

@skirnir: Vielleicht ist selbst das uninteressant wenn Du bei der `get_payload()`-Methode für das `decode`-Argument `True` übergibst. :-)
skirnir
User
Beiträge: 33
Registriert: Sonntag 25. Januar 2015, 10:59

BlackJack hat geschrieben:@skirnir: Vielleicht ist selbst das uninteressant wenn Du bei der `get_payload()`-Methode für das `decode`-Argument `True` übergibst. :-)
:oops: Mal wieder zu früh aufgehört zu lesen. Danke!

Aber immerhin habe ich was über Exception-Handling gelernt.
Antworten