2015-12-26 8 views
6

Dire che ho le seguenti quattro variabili:Handling stesso tipo eccezioni a parte in Python

>>> f1 = (print, 1, 2 ,3 ,4) 
>>> f2 = (exit, 1, 2 ,3 ,4) 
>>> f3 = (1, 2, 3, 4) 
>>> f4 = 4 

In un programma ipotetica, mi aspetto che ciascuno di tali variabili per tenere una tupla, il cui primo elemento dovrebbe essere il nome di un funzione, e i cui elementi successivi dovrebbero essere detti parametri della funzione, nell'ordine.

potrei chiamare una funzione memorizzata in questo modo in questo modo:

>>> f1[0](*f1[1:]) 
1 2 3 4 

Tuttavia, la maggior parte di queste variabili non sono nel formato eccettuata, e mi piacerebbe essere in grado di incapsulare la chiamata dei loro interno try/except blocchi per gestire tali situazioni.

Ora, anche se le chiamate di funzione di f2, f3 e f4 pausa per motivi radicalmente diverso, tutti gettano lo stesso tipo di eccezione, un TypeError:

>>> f2[0](*f2[1:]) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: __call__() takes from 1 to 2 positional arguments but 5 were given 
>>> f3[0](*f3[1:]) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: 'int' object is not callable 
>>> f4[0](*f4[1:]) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: 'int' object is not subscriptable 

Così che facendo un generico:

try: 
    f[0](*f[1:]) 
except TypeError: 
    # handle exception 

Non fornire informazioni sufficienti per gestire ogni eccezione di conseguenza.

Quale sarebbe il modo corretto di distinguere tra distinte eccezioni dello stesso tipo in Python?

risposta

2

Quindi, è necessario utilizzare un metodo di chiamata diverso da function(*tuple). Ecco un esempio di una funzione fun_apply che chiama una funzione particolare con argomenti posizionali e parola chiave. Aggiunge un controllo esplicito per assicurarsi che args sia iterable e che kwargs erediti da collection.Mapping.

from collections import Mapping 

def fun_apply(f, args=None, kwargs=None):                     
    if args is None: 
     args = [] 
    if kwargs is None: 
     kwargs = {} 

    try: 
     args = iter(args) 
    except TypeError: 
     # handle args being non-iterable 
     pass 

    if isinstance(kwargs, collections.Mapping): 
     pass 
    else: 
     # handle kwargs being a non-mapping 
     pass 

    if hasattr(f, '__call__'): 
     pass 
    else: 
     # handle f being non-callable 
     pass 

    try: 
     f(*args, **kwargs) 
    except TypeError as e: 
     raise TypeError(e) 

L'altra opzione è quella di elaborare la stringa message esplicitamente, ma questo potrebbe avere conseguenze indesiderate e messaggi di errore si potrebbe differire tra le versioni di Python.

+0

Capisco che questi approcci funzionino nei casi in cui sto sollevando manualmente 'TypeError' (o una sottoclasse di esso). Come si applicano alle situazioni in cui l'eccezione viene sollevata senza il mio input diretto, come nelle mie funzioni di esempio? – zayora

+0

A destra, se si immette il numero errato di argomenti o argomenti di parole chiave non previste, si genera un errore di tipo "TypeError" e il corpo della funzione non viene valutato. Comunque se usi qualcosa come 'fun_apply', puoi prendere questo' TypeError' e lanciare una nuova eccezione, 'TypeError' o altrimenti, che avvolge la funzione chiamata. –

+0

Ma cosa succede se non è quello che voglio il mio blocco 'try'/except' da fare in tutti i casi? Che cosa succede se voglio solo catturare il caso in cui una funzione appropriata (o callable) come "exit" viene chiamata con troppi (o troppo pochi) parametri, e voglio stampare un avviso quando ciò accade, ma voglio comunque che il mio programma si blocca e brucia quando il primo elemento della tupla non è richiamabile (o la variabile non è affatto una tupla)? Come dovrei farlo? C'è qualche informazione in più che posso raccogliere dall'oggetto eccezione che mi permetterebbe di gestire correttamente queste situazioni? – zayora