Zrobiłbym to w ten sposób, aby zmiana jego typu foo()
nie wymagała również zmiany go bar()
.
def foo():
try:
raise IOError('Stuff')
except:
raise
def bar(arg1):
try:
foo()
except Exception as e:
raise type(e)(e.message + ' happens at %s' % arg1)
bar('arg1')
Traceback (most recent call last):
File "test.py", line 13, in <module>
bar('arg1')
File "test.py", line 11, in bar
raise type(e)(e.message + ' happens at %s' % arg1)
IOError: Stuff happens at arg1
Zaktualizuj 1
Oto niewielka modyfikacja, która zachowuje oryginalne dane śledzenia:
...
def bar(arg1):
try:
foo()
except Exception as e:
import sys
raise type(e), type(e)(e.message +
' happens at %s' % arg1), sys.exc_info()[2]
bar('arg1')
Traceback (most recent call last):
File "test.py", line 16, in <module>
bar('arg1')
File "test.py", line 11, in bar
foo()
File "test.py", line 5, in foo
raise IOError('Stuff')
IOError: Stuff happens at arg1
Zaktualizuj 2
W przypadku Pythona 3.x kod w mojej pierwszej aktualizacji jest niepoprawny składniowo, a pomysł posiadania message
atrybutu BaseException
został wycofany w zmianie na PEP 352 16.05.2012 (moja pierwsza aktualizacja została opublikowana 12.03.2012) . Tak więc obecnie, w Pythonie 3.5.2 i tak, musiałbyś zrobić coś wzdłuż tych linii, aby zachować śledzenie, a nie zakodować na stałe typ wyjątku w funkcji bar()
. Zauważ również, że będzie linia:
During handling of the above exception, another exception occurred:
w wyświetlanych komunikatach śledzenia.
# for Python 3.x
...
def bar(arg1):
try:
foo()
except Exception as e:
import sys
raise type(e)(str(e) +
' happens at %s' % arg1).with_traceback(sys.exc_info()[2])
bar('arg1')
Zaktualizuj 3
Komentator zapytał, czy istnieje sposób, który działałby zarówno w Pythonie 2, jak i 3. Chociaż odpowiedź może wydawać się „Nie” ze względu na różnice składniowe, można to obejść, używając funkcji pomocniczej, takiej jak reraise()
w six
add- na module. Jeśli więc z jakiegoś powodu wolisz nie korzystać z biblioteki, poniżej znajduje się uproszczona wersja samodzielna.
Zauważ również, że ponieważ wyjątek jest ponownie wywoływany w reraise()
funkcji, pojawi się on w każdym wywołanym śledzeniu, ale ostateczny wynik jest taki, jaki chcesz.
import sys
if sys.version_info.major < 3: # Python 2?
# Using exec avoids a SyntaxError in Python 3.
exec("""def reraise(exc_type, exc_value, exc_traceback=None):
raise exc_type, exc_value, exc_traceback""")
else:
def reraise(exc_type, exc_value, exc_traceback=None):
if exc_value is None:
exc_value = exc_type()
if exc_value.__traceback__ is not exc_traceback:
raise exc_value.with_traceback(exc_traceback)
raise exc_value
def foo():
try:
raise IOError('Stuff')
except:
raise
def bar(arg1):
try:
foo()
except Exception as e:
reraise(type(e), type(e)(str(e) +
' happens at %s' % arg1), sys.exc_info()[2])
bar('arg1')
message
atrybutu Exception , znalazłem to pytanie SO, BaseException.message jest przestarzałe w Pythonie 2.6 , co wydaje się wskazywać, że jego użycie jest teraz odradzane (i dlaczego nie ma go w dokumentacji).