Biraz dekoratör tedavisi (Maybe monad ve kaldırmasından çok gevşek esinlenerek). Python 3.6 tipi ek açıklamaları güvenle kaldırabilir ve daha eski bir mesaj biçimlendirme stili kullanabilirsiniz.
fallible.py
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'
Ayrıca bu çözümü None
, except
parçadan biraz daha anlamlı bir şey döndürmek için değiştirebilirsiniz (veya çözümü fallible
'argümanlarında bu dönüş değerini belirterek çözümü genel hale getirebilirsiniz ).
exception
Yöntem basitçe çağırırerror(message, exc_info=1)
.exc_info
Bir istisna bağlamından günlük yöntemlerinden herhangi birine geçtiğinizde , bir geri izleme alırsınız.