Python: избегайте оценки короткого замыкания

Это проблема, которая возникла у меня во время работы над проектом 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 не будет оцениваться и его сообщения об ошибках будут отсутствовать.

Это только пример. Насколько мне известно, нет никакой жадной альтернативы and/or, как на других языках (т.е. Smalltalk). Я могу представить, что проблема возникает при разных обстоятельствах (и не только в Python). Решения, о которых я мог думать, - все это неудобные (вложенные ifs, присваивающие возвращаемые значения локальным переменным и использующие их в выражении if). Я хотел бы знать питоновский способ решения таких проблем.

Спасибо заранее!

Ответы

Ответ 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).

Ответ 2

Вы можете просто использовать двоичный оператор &, который будет выполнять логику AND без необходимости короткого замыкания на bools.

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