一个函数装饰器,使函数具有容错性(函数失败时静默)。
项目描述
- 作者
Alisue <lambdalisue@hashnote.net>
- 支持的Python版本
2.6, 2.7, 3.2, 3.3, 3.4
您经常编写如下静默失败的代码吗?
try:
# do what ever you need...
return "foo"
except:
# fail silently
return ""
这类代码常见于Django项目或程序,在产品模式下不应抛出任何异常。
tolerance是一个函数装饰器,可以将函数转换为容错函数;即使存在异常也不会抛出异常的函数。这个概念对于制作稳定的产品或prefer_int类型的代码非常有用,如使用说明部分所述。
请查阅在线文档以获取更多详细信息。
功能
将函数转换为容错函数
当装饰的函数不可调用时,返回substitute(默认为None)。当函数可调用时,返回substitute函数的“返回值”。
可以通过exceptions参数指定要忽略的异常类列表。
当将fail_silently=False传递给装饰的函数时,函数不会忽略异常(可以通过argument_switch_generator函数更改参数名称以创建开关函数)。
安装
使用pip如
$ pip install tolerance
使用方法
假设您需要一个函数,当可能时将字符串转换为整数。没有tolerance,您需要编写如下代码
>>> # without tolerance
>>> def prefer_int_withot_tolerance(x):
... try:
... return int(x)
... except:
... # fail silently
... return x
>>> prefer_int_withot_tolerance(0)
0
>>> prefer_int_withot_tolerance('0')
0
>>> prefer_int_withot_tolerance('zero')
'zero'
然而,使用tolerance,您只需要编写一行代码
>>> from tolerance import tolerate
>>> prefer_int = tolerate(lambda x: x)(int)
>>> prefer_int(0)
0
>>> prefer_int('0')
0
>>> prefer_int('zero')
'zero'
或者,您可以使用PEP-318中描述的函数装饰器tolerance
>>> from tolerance import tolerate
>>> @tolerate(lambda x: x)
... def prefer_int_318(x):
... return int(x)
>>> prefer_int_318(0)
0
>>> prefer_int_318('0')
0
>>> prefer_int_318('zero')
'zero'
上面的示例代码指定了tolerate函数的substitute参数,用于指定函数失败时返回的值(lambda x: x部分)。tolerate函数接受多个参数来配置函数的行为。这些参数在案例研究和API文档中有详细说明。
变更日志
- 版本 0.1.0
初始开发
手动测试了Python 2.4、2.5、2.7、3.2、3.3
- 版本 0.1.1
添加了switch快捷功能
停止支持Python 2.4和2.5
通过2to3支持Python 3.2和3.3
使用tox进行测试
案例研究
问题:我如何返回函数失败时的默认值?
使用substitute参数指定默认值,如下
>>> from tolerance import tolerate
>>> @tolerate(substitute='foo')
... def raise_exception():
... raise Exception
>>> raise_exception()
'foo'
问题:我如何根据传递的参数更改默认值?
将substitute参数指定为一个函数
>>> from tolerance import tolerate
>>> def substitute_function(*args, **kwargs):
... # do what ever you need, this example simply return 1st argument
... return args[0]
>>> @tolerate(substitute=substitute_function)
... def raise_exception(*args):
... raise Exception
>>> raise_exception('bar', 'hoge')
'bar'
问题:我如何让函数只忽略几个异常?
使用exceptions参数指定要忽略的异常。
>>> from tolerance import tolerate
>>> exceptions_ignored = (
... AttributeError,
... ValueError,
... )
>>> @tolerate(exceptions=exceptions_ignored)
... def raise_exception(x):
... if x == 0:
... raise AttributeError
... elif x == 1:
... raise ValueError
... else:
... raise KeyError
>>> raise_exception(0) is None
True
>>> raise_exception(1) is None
True
>>> raise_exception(2)
Traceback (most recent call last):
...
KeyError
问题:我如何在装饰的函数中禁用忽略异常?
将fail_silently=False传递给装饰的函数。
>>> from tolerance import tolerate
>>> @tolerate()
... def raise_exception():
... raise KeyError
>>> raise_exception() is None
True
>>> raise_exception(fail_silently=False)
Traceback (most recent call last):
...
KeyError
您可以通过指定新的切换函数来更改属性名。下面将进行解释。
问题:我如何全局禁用忽略异常?
将tolerate.disabled = True设置为全局禁用容忍。
>>> from tolerance import tolerate
>>> @tolerate()
... def raise_exception():
... raise KeyError
>>> raise_exception() is None
True
>>> tolerate.disabled = True
>>> raise_exception()
Traceback (most recent call last):
...
KeyError
>>> # rollback
>>> tolerate.disabled = False
问题:我如何以复杂的方式禁用忽略异常?
使用switch参数指定切换函数。
>>> from tolerance import tolerate
>>> DEBUG = False
>>> def switch_function(*args, **kwargs):
... # do what ever you need, this sample check kwargs and DEBUG
... # remove 'fail_silently' attribute and store
... fail_silently = kwargs.pop('fail_silently', True)
... if DEBUG or not fail_silently:
... # do not ignore exceptions. note that kwargs which does not
... # have 'fail_silently' is returned back.
... return False, args, kwargs
... # do ignore exceptions. note that kwargs which does not have
... # 'fail_silently' is returned back.
... return True, args, kwargs
>>> @tolerate(switch=switch_function)
... def raise_exception():
... raise KeyError
>>> raise_exception() is None
True
>>> raise_exception(fail_silently=False)
Traceback (most recent call last):
...
KeyError
>>> DEBUG = True
>>> raise_exception()
Traceback (most recent call last):
...
KeyError
问题:我只是想更改属性名,使切换函数过于复杂
使用argument_switch_generator来创建切换函数。
>>> from tolerance import tolerate
>>> from tolerance import argument_switch_generator
>>> switch_function = argument_switch_generator('quiet')
>>> @tolerate(switch=switch_function)
... def raise_exception():
... raise KeyError
>>> raise_exception() is None
True
>>> # you can use `quiet=False` instead of `fail_silently`
>>> raise_exception(quiet=False)
Traceback (most recent call last):
...
KeyError
>>> # raise_exception does not know fail_silently so ignore
>>> raise_exception(fail_silently=False) is None
True
>>> #
>>> # From Version 0.1.1
>>> #
>>> @tolerate(switch='quiet')
... def raise_exception():
... raise KeyError
>>> raise_exception() is None
True
>>> raise_exception(quiet=False)
Traceback (most recent call last):
...
KeyError
>>> raise_exception(fail_silently=False) is None
True
问题:我想仅在fail_silently=True传递时使函数忽略异常
使用default参数告诉argument_switch_generator函数
>>> from tolerance import tolerate
>>> from tolerance import argument_switch_generator
>>> switch_function = argument_switch_generator('fail_silently', default=False)
>>> @tolerate(switch=switch_function)
... def raise_exception():
... raise KeyError
>>> raise_exception() is None
Traceback (most recent call last):
...
KeyError
>>> raise_exception(fail_silently=True) is None
True
>>> #
>>> # From Version 0.1.1
>>> #
>>> @tolerate(switch=[None, False])
... def raise_exception():
... raise KeyError
>>> raise_exception() is None
Traceback (most recent call last):
...
KeyError
>>> @tolerate(switch={'default': False})
... def raise_exception():
... raise KeyError
>>> raise_exception() is None
Traceback (most recent call last):
...
KeyError
问题:我想在verbose=False传递时禁用忽略异常
使用reverse参数告诉argument_switch_generator函数
>>> from tolerance import tolerate
>>> from tolerance import argument_switch_generator
>>> switch_function = argument_switch_generator('verbose', reverse=True)
>>> @tolerate(switch=switch_function)
... def raise_exception():
... raise KeyError
>>> raise_exception() is None
True
>>> raise_exception(verbose=True)
Traceback (most recent call last):
...
KeyError
>>> #
>>> # From Version 0.1.1
>>> #
>>> @tolerate(switch={'argument_name': 'verbose', 'reverse': True})
... def raise_exception():
... raise KeyError
>>> raise_exception() is None
True
>>> raise_exception(verbose=True)
Traceback (most recent call last):
...
KeyError
问题:我想在装饰函数中使用fail_silently参数
使用keep参数告诉argument_switch_generator函数
>>> from tolerance import tolerate
>>> from tolerance import argument_switch_generator
>>> switch_function = argument_switch_generator('fail_silently', keep=True)
>>> @tolerate(switch=switch_function)
... def raise_exception(**kwargs):
... if 'fail_silently' in kwargs:
... raise KeyError
... return 'Failed!'
>>> raise_exception(fail_silently=True) is None
True
>>> raise_exception(fail_silently=False)
Traceback (most recent call last):
...
KeyError
>>> #
>>> # From Version 0.1.1
>>> #
>>> @tolerate(switch={'keep': True})
... def raise_exception(**kwargs):
... if 'fail_silently' in kwargs:
... raise KeyError
... return 'Failed!'
>>> raise_exception(fail_silently=True) is None
True
>>> raise_exception(fail_silently=False)
Traceback (most recent call last):
...
KeyError