La mia congettura è che se senti il bisogno di un tale aiuto, probabilmente stai ricevendo troppe eccezioni in primo luogo. Quale azione utile puoi intraprendere su un'eccezione? O conosci la causa dell'errore dal contesto (ovvero, ti aspetti l'eccezione) e puoi fornire una ragionevole strategia di fallback, quindi il tuo gestore generico non sarà di aiuto. O non sai cosa fare con l'eccezione, quindi dovresti semplicemente lasciarlo sgonfiare fino a quando qualcuno alla fine sarà in grado di agire su di esso in modo ragionevole. Come ultima risorsa, potresti avere un gestore "catch all" nella tua funzione principale che dice "sorry", registra l'eccezione e termina il programma. Per molti errori imprevisti, questa è la reazione appropriata.
Python è un po 'diverso dalla maggior parte delle altre lingue che conosco, nel senso che ti incoraggia ad usare le eccezioni molto più come una forma di flusso di controllo ordinario, ma non vedo come ciò cambierebbe l'immagine complessiva. Proprio come non hai una funzione di supporto generica per gestire i valori di ritorno, probabilmente non vuoi un gestore di eccezioni generico.
Lascia che ti illustri con alcuni esempi.
Questo è un uso ragionevole del rilevamento di un'eccezione che non può essere automatizzata.
def get_foo_factor(fallback=10):
try:
return int(os.getenv('FOO_FACTOR'))
except TypeError | ValueError:
# Environment variable not set or not an integer.
return fallback
Questo è completamente ridicolo.
def append_to_file(filename, message):
try:
with open(filename, 'a') as ostr:
print(message, file=ostr)
except TypeError:
print("Not a string?", file=sys.stderr)
except AttributeError:
print("This should never happen!", file=sys.stderr)
Se il tuo codice ha un sacco di tali except
cascate, il miglior refactoring potrebbe essere semplicemente cancellarle. Per quei pochi che rimangono, probabilmente troverai che il tuo gestore automatico non sarà di grande utilità. La lingua ha già una sintassi specializzata per rendere la gestione delle eccezioni il più comoda possibile, dopotutto.
L'unico caso d'uso per un gestore che riesco a vedere è se stai interagendo con una libreria che genera varie eccezioni e vuoi tradurle nel tuo schema. In questo caso, potrebbe essere appropriato qualcosa come il seguente:
def translate_libfoo_exception(exception):
try:
raise exception
except FooErrorOne as e:
return MyError(e)
except FooErrorTwo as e:
return MyOtherError(e)
except FooErrorThree as e:
return MyOtherError(e)
except FooError as e:
return MyGenericError(e)
except Exception as e:
return e
Potrebbe quindi essere usato in questo modo.
try:
foo.bar()
except FooErrorThree:
# Needs special handling
pass
except Exception as e:
# Cannot be handled, translate and re-raise
raise translate_libfoo_exception(e)