Python:避免短路评估

j0k*_*ker 21 python logical-operators

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

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

if form.is_valid():
    # code to save the form data
Run Code Online (Sandbox Code Playgroud)

is_valid() 不仅验证表单数据,还将错误消息添加到表单对象,然后可以向用户显示.

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

if form1.is_valid() and form2.is_valid():
    # ...
Run Code Online (Sandbox Code Playgroud)

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

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

提前致谢!

mgi*_*son 31

怎么样的:

if all([form1.is_valid(), form2.is_valid()]):
   ...
Run Code Online (Sandbox Code Playgroud)

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

if all([ form.is_valid() for form in (form1,form2) ])  
Run Code Online (Sandbox Code Playgroud)

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

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

  • 我花了几秒钟才拿出来.这是我以前没有考虑过的一个极端情况(我经常在Fortran工作,不保证短路,但允许它),我总是想弄清楚如何确保我的表达式被短路.弄清楚这对我有点倒退:). (2认同)

slo*_*oth 17

您可以简单地使用二元&运算符,它将在bools上执行非短路逻辑AND.

if form1.is_valid() & form2.is_valid():
   ...
Run Code Online (Sandbox Code Playgroud)

  • 我的解决方案的一个优点是,如果您的所有结果都是布尔值**("True","False","1"或"0"),则不仅限于`和`**.你可以写一个像`if foo()&baz()|这样的表达式 bar()`应该按预期运行. (4认同)
  • 更具体地说,它将对整数执行按位"和".因为bool碰巧是从"True == 1"和"False == 0"的整数派生出来的,所以这很有效.它不一定(必然)适用于其他类型或返回非布尔值的函数.不过,这是一个很好的工具(+1) (3认同)
  • 与此处的其他一些评论相反,这个答案是完全正确的.事实上,这是bools的专门设计和预期行为.`bool`甚至有自己的`bool .__和___`为`True&True`返回'True`而不是`1`,对于其他按位运算符也是如此,所以它不仅仅是继承int实现(尽管它是兼容的)用int行为). (3认同)
  • 这有一个潜在的陷阱,而“all”则没有——它只有在返回值实际上是布尔值时才起作用,它不会测试非布尔值的“真实性”。例如,“all([1, 2])”是“True”,因为“1”和“2”都是真值,但“1 & 2”是假值。在其他一些情况下,“&”会引发“TypeError”。 (2认同)