2015-12-26 16 views
6

że mam cztery następujące zmienne:Handling same wyjątki typu osobno w Pythonie

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

w hipotetycznym programu, spodziewam się każdej z tych zmiennych do przechowywania krotki, którego pierwsza pozycja powinna być nazwa Funkcja, której kolejne pozycje powinny być określonymi parametrami funkcji w kolejności.

mogę wywołać funkcję przechowywanych w ten sposób tak:

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

Jednak większość z tych zmiennych nie są w wyłączonych formacie, i chciałbym, aby móc ująć powołanie z nich wewnątrz try/ bloki w celu obsługi tych sytuacji.

Teraz, mimo wywołania funkcji z f2, f3 i f4 przerwą na radykalnie innego powodu, wszyscy rzucają ten sam rodzaj wyjątku 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 

Tak, że robi to ogólny:

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

Nie dostarczyłoby mi wystarczających informacji, aby odpowiednio obsługiwać każdy wyjątek.

Jaki byłby właściwy sposób rozróżniania różnych wyjątków tego samego typu w Pythonie?

Odpowiedz

2

Musisz więc użyć innej metody wywoływania niż function(*tuple). Oto przykład funkcji fun_apply, która wywołuje określoną funkcję z argumentami pozycyjnymi i słowami kluczowymi. Dodaje wyraźną kontrolę, aby upewnić się, że args jest iterowalna, a kwargs dziedziczy po 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) 

Inną opcją jest przetwarzanie ciąg message wyraźnie, ale to może mieć niezamierzone konsekwencje i komunikaty o błędach mogą się różnić między wersjami Pythona.

+0

Rozumiem, że metody te działają w przypadkach, w których ręcznie podnoszę "TypeError" (lub jego podklasę). Jak miałyby one zastosowanie w sytuacjach, w których wyjątek jest zgłaszany bez mojego bezpośredniego wkładu, na przykład w moich przykładowych funkcjach? – zayora

+0

W prawo, jeśli wpiszesz niewłaściwą liczbę argumentów lub nieoczekiwanych argumentów słów kluczowych, podniesiesz "TypeError", a treść twojej funkcji nie zostanie oceniona. Jednak jeśli użyjesz czegoś takiego jak 'fun_apply', możesz złapać to' TypeError' i rzucić nowy wyjątek, 'TypeError' lub inaczej, który zawinie wywoływaną funkcję. –

+0

Ale co, jeśli nie to, co chcę zrobić, aby mój blok 'try' /' except' zrobił we wszystkich przypadkach? Co jeśli chcę tylko złapać przypadek, w którym wywoływana jest odpowiednia funkcja (lub wywoływana) jak 'exit' z zbyt dużą liczbą (lub zbyt małą liczbą) parametrów i chcę wydrukować ostrzeżenie, gdy tak się stanie, ale nadal chcę, aby mój program awarii i wypalenia, gdy pierwszy element krotki nie jest wywoływalny (lub zmienna nie jest w ogóle krotką)? Jak powinienem to zrobić? Czy są jakieś dodatkowe informacje, które mogę zebrać z obiektu wyjątku, który pozwoliłby mi właściwie obsłużyć te sytuacje? – zayora