Ein bisschen Dekorationsbehandlung (sehr locker inspiriert von der Vielleicht-Monade und dem Heben). Sie können Anmerkungen vom Typ Python 3.6 sicher entfernen und einen älteren Formatierungsstil für Nachrichten verwenden.
fehlbar
from functools import wraps
from typing import Callable, TypeVar, Optional
import logging
A = TypeVar('A')
def fallible(*exceptions, logger=None) \
-> Callable[[Callable[..., A]], Callable[..., Optional[A]]]:
"""
:param exceptions: a list of exceptions to catch
:param logger: pass a custom logger; None means the default logger,
False disables logging altogether.
"""
def fwrap(f: Callable[..., A]) -> Callable[..., Optional[A]]:
@wraps(f)
def wrapped(*args, **kwargs):
try:
return f(*args, **kwargs)
except exceptions:
message = f'called {f} with *args={args} and **kwargs={kwargs}'
if logger:
logger.exception(message)
if logger is None:
logging.exception(message)
return None
return wrapped
return fwrap
Demo:
In [1] from fallible import fallible
In [2]: @fallible(ArithmeticError)
...: def div(a, b):
...: return a / b
...:
...:
In [3]: div(1, 2)
Out[3]: 0.5
In [4]: res = div(1, 0)
ERROR:root:called <function div at 0x10d3c6ae8> with *args=(1, 0) and **kwargs={}
Traceback (most recent call last):
File "/Users/user/fallible.py", line 17, in wrapped
return f(*args, **kwargs)
File "<ipython-input-17-e056bd886b5c>", line 3, in div
return a / b
In [5]: repr(res)
'None'
Sie können diese Lösung auch so ändern, dass sie etwas aussagekräftigeres als None
das except
Teil zurückgibt (oder die Lösung generisch machen, indem Sie diesen Rückgabewert in fallible
den Argumenten angeben).
exception
Methode ruft einfach auferror(message, exc_info=1)
. Sobald Sieexc_info
aus einem Ausnahmekontext an eine der Protokollierungsmethoden übergeben, erhalten Sie einen Traceback.