python

Python 3.5: exceptions

Folgendes ist mit Python 3 syntaktisch nicht mehr erlaubt:

try: pass
except:
 pass

try: pass
except ExceptionType, var:
 pass

try: pass
except ExceptionType as (a, b, c):
 pass

Statt dessen sollte man die neue Syntax verwenden:

try: pass
except Exception:
 pass

try: pass
except ExceptionType1 as var:
 pass

try: pass
except (ExceptionType1, ExceptionType2) as var:
 pass

Eine wichtige Änderung in Python 3 ist auch, das var nach der Abarbeitung des Exception-Blocks gelöscht wird! Das entspricht in Python 2 also in etwa folgendem Block:

try: pass
except ExceptionType1 as var:
 try:
   pass
 finally:
   del var

Hintergrund für die Umstellung war u.a. der, dass Exceptions eine Referenz auf den Stacktrace enthalten. Damit ist nicht die textuelle Ansicht gemeint, sondern Referenzen auf alle Python-internen Datenstrukturen für Stack-Frames und ähnliches. Diese enthalten wiederum Referenzen auf alle lokale Variablen der aufgerufenen Funktionen, was u.a. dazu führt, dass diese noch nicht durch den Garbage-Collector freigegeben werden können. Dieses Verhalten auch auch schon in UMC zu einem Memory-Leak geführt. Möchte man also nach der Behandlung einer Ausnahme noch auf diese zugreifen, muss man eine Referenz nun explizit darauf anlegen.

args

In Python 2 konnte man man auch direkt über Exception iterieren:

try: pass
except ExceptionType as (a, b, c):
 pass

Das funktioniert mit Python 3 nicht mehr und mann muss explizit auf args zugreifen:

try: pass
except ExceptionType as ex:
 (a, b, c) = ex.args
 pass

re-raise

raise "String" ist schon lange nicht mehr erlaubt. Mit Python 3 ist aber auch ein raise Exception, Exception(), Traceback() nicht mehr erlaubt. Ersatz bietet six.reraise. Ein einfaches raise zu weiterreichen der letzten Ausnahme funktioniert aber weiterhin.

Alternativ kann man eine neue Exception werfen und die alte als Ursache anhängen: raise NewException() from ex.

Written on March 11, 2020