如何防止短路评估?
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 中)。我能想到的解决方案都是笨拙的(嵌套if
s,将返回值分配给局部变量并在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提供的解决方案结合使用,因为any
和all
返回布尔值。【参考方案2】:
您可以简单地使用二进制&
运算符,它将在布尔值上执行非短路逻辑AND。
if form1.is_valid() & form2.is_valid():
...
【讨论】:
更具体地说,它将对整数执行按位and
。由于 bool 恰好是从具有 True == 1
和 False == 0
的整数派生的,因此这是可行的。它不会(必然)适用于其他类型或返回非布尔值的函数。尽管如此,它仍然是一个很好的工具(+1)
绝对比 mgilson 的解决方案简单。感谢那!另一个可能对其他阅读代码的人更有帮助。在这里,我猜你可能认为我只是混淆了and
和&
。
与我的解决方案相比,一个优势是您不仅限于and
如果所有结果都是布尔值 (True
,False
,1
或0
)。您可以编写像 if foo() & baz() | bar()
这样的表达式,它的行为应该符合预期。
与这里其他一些 cmets 所说的相反,这个答案是完全正确的。事实上,这是专门设计和预期的布尔行为。 bool
甚至有自己的bool.__and__
,它返回True
而不是1
的True & True
,对于其他位运算符也是如此,因此它不仅仅是继承 int 实现(尽管它与 int 行为兼容)。
这有一个潜在的陷阱,all
没有 - 它仅在返回值实际上是布尔值时才有效,它不会测试“非布尔值的真实性”。例如,all([1, 2])
是 True
,因为 1
和 2
都是真值,但 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`
【讨论】:
以上是关于如何防止短路评估?的主要内容,如果未能解决你的问题,请参考以下文章
为啥短路不能防止与逻辑 AND (&&) 的不可达分支相关的 MissingMethodException?
斯坦福大学公开课机器学习: advice for applying machine learning - evaluatin a phpothesis(怎么评估学习算法得到的假设以及如何防止过拟合或欠
Visual Studio 2017 调试错误:为了防止在评估函数 *.toString 时发生不安全的中止,所有线程都被允许运行