Jaki jest najlepszy sposób uzyskiwania komunikatów o wyjątkach ze składników biblioteki standardowej w Pythonie?
Zauważyłem, że w niektórych przypadkach można to uzyskać za pośrednictwem message
takiego pola:
try:
pass
except Exception as ex:
print(ex.message)
ale w niektórych przypadkach (na przykład w przypadku błędów gniazda) musisz zrobić coś takiego:
try:
pass
except socket.error as ex:
print(ex)
Zastanawiałem się, czy istnieje standardowy sposób na opisanie większości tych sytuacji?
python
exception
exception-handling
Zamrożone serce
źródło
źródło
except Foo as bar:
jest to to samo, coexcept Foo, bar:
(z wyjątkiem tego, że pierwsza jest nowsza i będzie działać w 3.x), niezależnie od tego, czy błąd występuje zmessage
atrybutem, czy nie..message
w przypadku błędu jest standardowy, czy nie?print(msg)
to tylko skrót doprint(str(msg))
message
jest przestarzały.Odpowiedzi:
Jeśli przejrzysz dokumentację dotyczącą błędów wbudowanych , zobaczysz, że większość
Exception
klas przypisuje pierwszy argument jakomessage
atrybut. Nie wszyscy jednak.Warto zauważyć, że
EnvironmentError
(z podklasamiIOError
iOSError
) ma pierwszy argumenterrno
, drugi zstrerror
. Nie mamessage
...strerror
jest mniej więcej analogiczne do tego, co normalnie byłobymessage
.Mówiąc bardziej ogólnie, podklasy
Exception
mogą robić, co chcą. Mogą miećmessage
atrybut lub nie . Przyszłe wbudowane elementyException
mogą nie miećmessage
atrybutu. ŻadnaException
podklasa zaimportowana z bibliotek innych firm lub kod użytkownika może nie miećmessage
atrybutu.Myślę, że właściwym sposobem radzenia sobie z tym jest zidentyfikowanie konkretnych
Exception
podklas, które chcesz wyłapać, a następnie wyłapanie tylko tych, a nie wszystkiego za pomocą znakuexcept Exception
, a następnie wykorzystanie dowolnych atrybutów, które określona podklasa definiuje, jak chcesz.Jeśli musisz
print
coś, myślę, że drukowanie złapanegoException
samego siebie najprawdopodobniej zrobi to, co chcesz, bez względu na to, czy mamessage
atrybut, czy nie.Możesz również sprawdzić atrybut wiadomości, jeśli chcesz, w ten sposób, ale tak naprawdę nie sugerowałbym tego, ponieważ wydaje się po prostu niechlujny:
try: pass except Exception as e: # Just print(e) is cleaner and more likely what you want, # but if you insist on printing message specifically whenever possible... if hasattr(e, 'message'): print(e.message) else: print(e)
źródło
str(ex)
zamiast po prostuex
?print()
automatycznie dzwonistr()
do Ciebie. Nie ma powodu, aby ręcznie wywoływać to samo, chociaż jest to nieszkodliwe, ponieważ wywołaniestr()
łańcucha po prostu zwróci sam ciąg.str()
typem wiadomościunicode
.Aby poprawić odpowiedź udzieloną przez @artofwarfare , oto, co uważam za lepszy sposób na sprawdzenie
message
atrybutu i wydrukowanie go lub wydrukowanieException
obiektu jako rezerwy.try: pass except Exception as e: print getattr(e, 'message', repr(e))
Wywołanie
repr
jest opcjonalne, ale uważam, że w niektórych przypadkach jest konieczne.Aktualizacja nr 1:
Po komentarzu @MadPhysicist , oto dowód, dlaczego wezwanie do
repr
może być konieczne. Spróbuj uruchomić następujący kod w swoim interpreterze:try: raise Exception except Exception as e: print(getattr(e, 'message', repr(e))) print(getattr(e, 'message', str(e)))
Aktualizacja nr 2:
Oto demo ze specyfikacjami dla Pythona 2.7 i 3.5: https://gist.github.com/takwas/3b7a6edddef783f2abddffda1439f533
źródło
getattr
zgłasza wyjątek, jeśli przekazany obiekt nie ma żądanego atrybutu. Jeśli chcesz zrobić coś takiego, myślę, że należy użyć opcjonalnego trzeciego argumentu zagetattr
coś takiego:print getattr(e, 'message', e)
. Zdecydowanie lepsze niż to, co zrobiłem. Inną opcją byłobyprint(e.message if hasattr(e, 'message') else e)
.str
zamiast tegorepr
.str
,repr
po prostu dodaje nazwę klasy. Zamiast używaćrepr
, proponuję użyćprint('{e.__class__.__name__}: {e}'.format(e=e))
. Wydruk jest czystszy i przylega do wyjścia samoczynnego podnoszenia.'{e.__class__.__module__}.{e.__class__.__name__}: {e}'
repr(e)
było na razie jedynym rozwiązaniem, które pomogło mi wydrukować co najmniej minimalną ilość informacji o błędzie, który wyłapałem w określonych okolicznościach.repr(e)
dajeKeyError(0,)
(co jest tym, czym jest błąd), odpowiednio tylko podczasstr(e)
lube.message
przyniosło,0
albo wcale.Miałem ten sam problem. Myślę, że najlepszym rozwiązaniem jest użycie log.exception, który automatycznie wydrukuje ślad stosu i komunikat o błędzie, taki jak:
try: pass log.info('Success') except: log.exception('Failed')
źródło
log
? Właśnie wypróbowałemimport log
Python 2.7.13 i otrzymałem komunikat, że nie ma modułu o takiej nazwie. Czy jest to coś, co dodałeś przez,pip
czy też zostało dodane w nowszej wersji Pythona (wiem, wiem, muszę zaktualizować do Pythona 3 ... Zrobię to tak szybko, jak CentOS domyślnie przestanie być dostarczany z Pythonem 2 ...)import logging
\ nlog = logging.getLogger(__name__)
Ja też miałem ten sam problem. Zagłębiając się w to, odkryłem, że klasa Exception ma
args
atrybut, który przechwytuje argumenty użyte do utworzenia wyjątku. Jeśli zawęzisz wyjątki, które będą przechwytywać poza, do podzbioru, powinieneś być w stanie określić, w jaki sposób zostały skonstruowane, a tym samym, który argument zawiera wiadomość.try: # do something that may raise an AuthException except AuthException as ex: if ex.args[0] == "Authentication Timeout.": # handle timeout else: # generic handling
źródło