适用于多种条件的Python设计模式 [英] Python design pattern for many conditions

查看:114
本文介绍了适用于多种条件的Python设计模式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在许多条件下编写验证函数的推荐结构是什么?请参阅这两个示例。第一个看起来很丑陋,第二个不是很常见,可能是因为 assert 通常用于排除意外行为。还有更好的选择吗?

What is the recommended structure to write validate functions with many conditions? See these two examples. The first looks ugly, the second isn't very common, perhaps because assert is generally used to rule out unexpected behaviour. Are there better alternatives?

def validate(val):
  if cond1(val):
    return False
  if cond2(val):
    return False
  if cond3(val)
    return False
  return True

def validate(val):
  try:
    assert cond1(val)
    assert cond2(val)
    assert cond3(val)
    return True
  except AssertionError:
    return False


推荐答案

编写该函数的一种简便方法是使用 any 和一个生成器表达式:

A compact way to write that function is to use any and a generator expression:

def validate(val):
    conditions = (cond1, cond2, cond3)
    return not any(cond(val) for cond in conditions)

any all 函数短路,因此它们将立即停止测试因为它们有确定的结果,即 any 一旦击中True-ish就停止值,全部一旦达到虚假值就停止,因此这种形式的测试非常有效。

The any and all functions short-circuit, so they'll stop testing as soon as they have a definite result, i.e., any stops as soon as it hits a True-ish value, all stops as soon as it hits a False-ish value, so this form of testing is quite efficient.

我还应该提到,将这样的生成器表达式传递给 all / any 更为有效。 code>而不是列表理解。因为 all / any 一旦获得有效结果,就会立即停止测试,因此如果您从生成器中获取它们,生成器也会停止,因此在上面的代码中,如果 cond(val)的计算结果为True-ish值,则不会再测试其他条件。但是,如果您通过 all / any 进行列表理解,例如 any([cond(val )(对于条件中的条件))必须在 all / any 甚至可以开始测试。

I should also mention that it's much more efficient to pass a generator expression like this to all / any than a list comprehension. Because all / any stop testing as soon as they get a valid result, if you feed them from a generator then the generator will stop too, thus in the above code if cond(val) evaluates to a True-ish value no further conditions will be tested. But if you pass all / any a list comprehension, eg any([cond(val) for cond in conditions]) the whole list has to be be built before all / any can even start testing.

您尚未向我们展示您的的内部结构cond 函数,但是您确实在问题中提到了 assert ,所以我觉得这里的注释是适当的。

You haven't shown us the internal structure of your cond functions, but you did mention assert in your question, so I feel that the following remarks are in order here.

正如我在评论中提到的, assert 不应用于验证数据,而应用于验证程序逻辑。 (此外,可以通过-O命令行选项禁用断言处理)。用于具有无效值的数据的正确异常是 ValueError ,对于类型错误的对象,请使用 TypeError 。但是请记住,异常是为处理特殊情况而设计的。

As I mentioned in the comments, assert should not be used to validate data, it's used to validate program logic. (Also, assertion-handling can be disabled via an -O command line option). The correct Exception to use for data with invalid values is ValueError, and for objects that are the wrong type, use TypeError. But bear in mind that exceptions are designed to handle situations that are exceptional.

如果您预计会收到大量格式错误的数据,那么通常使用基于 if 的逻辑要比例外更为有效。如果未真正引发异常,Python异常处理将非常快,事实上,它比等效的 if 代码要快。但是,如果引发异常的时间超过5-10%,则基于 try ... except 的代码将明显慢于 if 基于等价物。

If you expect a lot of malformed data then it's generally more efficient to use if based logic than exceptions. Python exception-handling is quite fast if the exception isn't actually raised, in fact it's faster than the equivalent if based code. However, if the exception is raised say more than 5-10% of the time, then the try...except based code will be noticeably slower than the if based equivalent.

当然,有时使用例外是唯一明智的选择,即使情况并非如此。一个典型的例子是将一组数字字符串转换为实际的数字对象时,代表整数的字符串将转换为整数对象,其他数字字符串将转换为浮点数,而其他字符串保留为字符串。在Python中执行此操作的标准方法包括使用异常。 例如

Of course, sometimes using exceptions is the only sensible option, even though the situation isn't all that exceptional. A classic example is when you're converting a collection of numeric strings to actual numeric objects, so that strings that represent integers get converted to integer objects, other numeric strings get converted to floats, and other strings get left as strings. The standard way to do this in Python involves using exceptions. For example:

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 "Look Before You Leap" logic here is possible here, but it makes the code more complicated because you need to deal with possible minus signs and scientific notation.

这篇关于适用于多种条件的Python设计模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆