如何防止短路评估?

Posted

技术标签:

【中文标题】如何防止短路评估?【英文标题】:How to prevent short-circuit evaluation? 【发布时间】:2012-08-30 04:11:40 【问题描述】:

这是我在处理 Django 项目时遇到的问题。这是关于表单验证的。

在Django中,当你有一个提交的表单时,你可以在对应的表单对象上调用is_valid()来触发验证并返回一个布尔值。所以,通常你的视图函数中有这样的代码:

if form.is_valid():
    # code to save the form data

is_valid() 不仅会验证表单数据,还会将错误消息添加到表单对象中,然后显示给用户。

在一个页面上,我同时使用了两个表单,并且还希望仅当两个表单都包含有效数据时才保存数据。这意味着在执行代码以保存数据之前,我必须在两个表单上调用is_valid()。最明显的方式:

if form1.is_valid() and form2.is_valid():
    # ...

由于逻辑运算符的短路评估而无法工作。如果form1 无效,form2 将不会被评估并且其错误消息将丢失。

这只是一个例子。据我所知,在其他语言(即 Smalltalk)中,没有比 and/or 更贪婪的替代品。我可以想象在不同的​​情况下会出现这个问题(不仅在 Python 中)。我能想到的解决方案都是笨拙的(嵌套ifs,将返回值分配给局部变量并在if 语句中使用它们)。我想知道解决这类问题的pythonic方法。

【问题讨论】:

【参考方案1】:

怎么样:

if all([form1.is_valid(), form2.is_valid()]):
   ...

在一般情况下,可以使用列表理解,以便预先计算结果(与此上下文中常用的生成器表达式相反)。例如:

if all([ form.is_valid() for form in (form1,form2) ])  

这也可以很好地扩展到任意数量的条件......唯一的问题是它们都需要通过“and”而不是if foo and bar or baz: ...连接。

(对于非短路or,您可以使用any 而不是all)。

【讨论】:

正是我所寻找的。谢谢! 我花了几秒钟才想到这个。这是我以前没有考虑过的一个极端情况(我经常在 Fortran 中工作,它不能保证短路,但允许它),我一直在试图弄清楚如何确保我的表达式被短路。弄清楚这一点对我来说有点倒退:)。 是的 all 是去这里的方式,但是你在哪里使用列表理解?我只在您的示例中看到了一个简单的列表。 @rantanplan -- 你是对的。 (哎呀)。我在想在一般情况下可以使用列表理解。我会解决的。 还要注意,上面的表格可以和@BigYellowCactus提供的解决方案结合使用,因为anyall返回布尔值。【参考方案2】:

您可以简单地使用二进制& 运算符,它将在布尔值上执行非短路逻辑AND

if form1.is_valid() & form2.is_valid():
   ...

【讨论】:

更具体地说,它将对整数执行按位and。由于 bool 恰好是从具有 True == 1False == 0 的整数派生的,因此这是可行的。它不会(必然)适用于其他类型或返回非布尔值的函数。尽管如此,它仍然是一个很好的工具(+1) 绝对比 mgilson 的解决方案简单。感谢那!另一个可能对其他阅读代码的人更有帮助。在这里,我猜你可能认为我只是混淆了and& 与我的解决方案相比,一个优势是您不仅限于and 如果所有结果都是布尔值 (True,False,10)。您可以编写像 if foo() & baz() | bar() 这样的表达式,它的行为应该符合预期。 与这里其他一些 cmets 所说的相反,这个答案是完全正确的。事实上,这是专门设计和预期的布尔行为。 bool 甚至有自己的bool.__and__,它返回True 而不是1True & True,对于其他位运算符也是如此,因此它不仅仅是继承 int 实现(尽管它与 int 行为兼容)。 一个潜在的陷阱,all 没有 - 它仅在返回值实际上是布尔值时才有效,它不会测试“非布尔值的真实性”。例如,all([1, 2])True,因为 12 都是真值,但 1 & 2 是假的。在其他一些情况下,& 会引发 TypeError【参考方案3】:

您可以使用Infix operators(ActiveState Python 配方)来定义您自己的布尔运算符:

aand = Infix(lambda x,y: bool(x) and bool(y))
1 |aand| 2  # Will return `True` instead of `1`

【讨论】:

以上是关于如何防止短路评估?的主要内容,如果未能解决你的问题,请参考以下文章

防止 Bash 短路

为啥短路不能防止与逻辑 AND (&&) 的不可达分支相关的 MissingMethodException?

斯坦福大学公开课机器学习: advice for applying machine learning - evaluatin a phpothesis(怎么评估学习算法得到的假设以及如何防止过拟合或欠

如何防止 CSS 渲染阻止我的网站?

Visual Studio 2017 调试错误:为了防止在评估函数 *.toString 时发生不安全的中止,所有线程都被允许运行

三元运算符可以等效于与逻辑运算符的短路吗?