编写该函数的一种紧凑方法是使用any
和一个生成器表达式:
def validate(val):
conditions = (cond1, cond2, cond3)
return not any(cond(val) for cond in conditions)
The any
and all
功能短路,所以一旦有确定的结果就会停止测试,即any
一旦达到 True-ish 值就停止,all
一旦达到 False 值就会停止,因此这种形式的测试非常有效。
我还应该提到的是much将这样的生成器表达式传递给更有效all
/ any
比列表理解。因为all
/ any
一旦获得有效结果就停止测试,如果您从生成器提供它们,则生成器也会停止,因此在上面的代码中,如果cond(val)
评估为 True-ish 值,不会测试进一步的条件。但如果你通过了all
/ any
列表理解,例如any([cond(val) for cond in conditions])
整个列表必须之前构建all
/ any
甚至可以开始测试。
你还没有向我们展示你的内部结构cond
功能,但你确实提到assert
对于你的问题,我认为以下评论是合适的。
正如我在评论中提到的,assert
不应该用于验证数据,它用于验证程序逻辑。 (此外,可以通过 -O 命令行选项禁用断言处理)。用于具有无效值的数据的正确异常是ValueError
,对于类型错误的对象,请使用TypeError
。但请记住,异常是为了处理异常情况而设计的。
如果您预计会出现大量格式错误的数据,那么使用通常会更有效if
基于逻辑而不是异常。如果实际上没有引发异常,Python 异常处理速度相当快,事实上它比同等情况更快if
基于代码。然而,如果异常发生的次数超过 5-10%,那么try...except
基于的代码将明显慢于if
基于等效。
当然,有时使用异常是唯一明智的选择,即使情况并非那么特殊。一个典型的示例是,当您将数字字符串集合转换为实际数字对象时,表示整数的字符串将转换为整数对象,其他数字字符串将转换为浮点数,而其他字符串将保留为字符串。在 Python 中执行此操作的标准方法涉及使用异常。例如 https://stackoverflow.com/a/5609191/4014959:
def convert(s):
''' Convert s to int or float, if possible '''
try:
return int(s)
except ValueError:
try:
return float(s)
except ValueError:
return s
data = ['42', 'spam', '2.99792458E8']
out = [convert(u) for u in data]
print(out)
print([type(u) for u in out])
output
[42, 'spam', 299792458.0]
[<class 'int'>, <class 'str'>, <class 'float'>]
Using “三思而后行” https://docs.python.org/3/glossary.html#term-lbyl这里的逻辑是possible在这里,但这使代码变得更加复杂,因为您需要处理可能的减号和科学记数法。