我喜欢 Raydel Miranda's answer 使用函数装饰器前置条件。这里有一种类似的方法,它不使用装饰器,而是使用内省和 eval
。它可能不太高效,但可以说更加简洁和表达力强。
import inspect
class ValidationError(ValueError):
pass
def validate(assertion, exc=ValidationError, msg=''):
"""
Validate the given assertion using values
from the calling function or method. By default,
raises a `ValidationException`, but optionally
raises any other kind of exeception you like.
A message can be provided, and will be formatted
in the context of the calling function. If no
message is specified, the test assertion will be
recapitulated as the cause of the exception.
"""
frame = inspect.currentframe().f_back
f_locals, f_globals = frame.f_locals, frame.f_globals
result = eval(assertion, f_globals, f_locals)
if result:
return
else:
if msg:
msg = msg.format(**f_locals)
else:
msg = 'fails test {0!r}'.format(assertion)
raise(exc(msg))
def r(name):
validate('isinstance(name, str)', msg='name must be str (was {name!r})')
validate('name.strip() != ""', msg='name must be non-empty (was {name!r})')
print(name,)
def r2(name, age):
validate('isinstance(name, str)', TypeError, 'name must be str (was {name!r})')
validate('name.strip() != ""', ValueError, 'name must be non-empty (was {name!r})')
validate('isinstance(age, int)', TypeError, 'age must be int (was {age!r})')
validate('age >= 0', ValueError, 'age must be non-negative (was {age!r})')
print(name,)
r('Joe')
r('')
r2('Dale', -3)
r2('Dale', None)
这将引发诸如以下的异常:
ValidationError: name must be non-empty (was '')
还有一个好处:如果您没有指定任何消息,它仍然会给出合理的输出。例如:
def r2simple(name, age):
validate('isinstance(name, str)')
validate('name.strip() != ""')
validate('isinstance(age, int)')
validate('age >= 0')
print(name,)
r2simple('Biff', -1)
返回:
ValidationError: fails test 'age >= 0'
这将在Python 2或3下工作。
TypeError
适用于“将操作或函数应用于不合适类型的对象”。严格来说 - 在执行操作时,更倾向于将其视为 TypeError(“让它失败”),还是将其视为验证错误(ValueError)?我正在看短语“操作或函数接收参数”与“将操作或函数应用于对象”,如果这有意义的话。(我理解在这种特定情况下 None 是错误的类型。) - Curtis MattoonValueError
不是一个“验证错误”。这更像是一个AssertionError
。TypeError
和ValueError
之间的区别仅仅是一个问题:“不适当的对象是否具有正确的类型?”如果是,就引发一个ValueError
。否则,引发一个TypeError
。这两个异常基本上是相同的东西;它们都意味着我们遇到了一个不适当的对象。 - user2555451