2012-09-05 27 views
18

Dies ist ein Problem, das mir bei der Arbeit an einem Django-Projekt aufgefallen ist. Es geht um Formularvalidierung.Python: Vermeiden Sie Kurzschlussauswertung

In Django können Sie bei einem übermittelten Formular is_valid() für das entsprechende Formularobjekt aufrufen, um die Validierung auszulösen und einen booleschen Wert zurückzugeben. Also, in der Regel haben Sie Code wie das in Ihrer Ansicht Funktionen:

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

is_valid() nicht validiert die Daten nur Form, sondern auch fügt Fehlermeldungen in das Formular-Objekt, das anschließend dem Benutzer angezeigt werden kann.

Auf einer Seite verwende ich zwei Formulare zusammen und möchte auch, dass die Daten nur gespeichert werden, wenn beide Formulare gültige Daten enthalten. Das bedeutet, dass ich is_valid() in beiden Formularen aufrufen muss, bevor der Code zum Speichern der Daten ausgeführt wird. Die naheliegendste Methode:

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

funktioniert nicht wegen der Kurzschlussauswertung von logischen Operatoren. Wenn form1 nicht gültig ist, wird form2 nicht ausgewertet und seine Fehlermeldungen fehlen.

Das ist nur ein Beispiel. Soweit ich weiß, gibt es keine gierige Alternative zu and/or wie in anderen Sprachen (d. H. Smalltalk). Ich kann mir vorstellen, dass dieses Problem unter anderen Umständen (und nicht nur in Python) auftritt. Die Lösungen, die ich mir vorstellen kann, sind allesamt plump (geschachtelte ifs, die Rückgabewerte lokalen Variablen zuweisend und sie in der if-Anweisung verwenden). Ich würde gerne den pythonischen Weg kennen, um diese Art von Problemen zu lösen.

Vielen Dank im Voraus!

Antwort

27

Wie sei es so etwas wie:

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

In einem allgemeinen Fall eine Liste Verständnis verwendet werden könnte, so dass die Ergebnisse vorne berechnet werden (im Gegensatz zu einem Generator Ausdruck gegenüber, die häufig in diesem Zusammenhang verwendet wird) . z.B .:

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

dies auch zu einer beliebigen Anzahl von Bedingungen gut skalieren wird ... Der einzige Haken ist, dass sie alle durch „and“ verbunden werden müssen, als zu if foo and bar or baz: ... gegenüber.

(für einen nicht-Kurzschluss or, könnten Sie any statt all verwenden).

+0

Genau das, was ich suchte. Vielen Dank! – j0ker

+2

Ich brauchte ein paar Sekunden, um das zu erreichen. Es ist ein Eckfall, den ich vorher nicht bedacht hatte (ich arbeite oft in Fortran, was keinen Kurzschluss garantiert, aber es zulässt) und ich versuche immer herauszufinden, wie ich sicherstellen kann, dass meine Ausdrücke kurzgeschlossen sind. Das herauszufinden, war für mich etwas rückläufig :). – mgilson

+0

Ja, das 'all' ist der Weg dorthin, aber wo hast du List-Comprehensions benutzt? Ich sehe nur eine einfache Liste in Ihrem Beispiel. – rantanplan

16

Sie können einfach den binären &-Operator verwenden, der eine nicht-Kurzschluss-Logik AND on bools macht.

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

Genauer gesagt, es wird ein bitweises "und" auf ganze Zahlen tun. Da Boole aus Ganzzahlen mit "True == 1" und "False == 0" abgeleitet werden, funktioniert dies. Es funktioniert nicht (notwendigerweise) für andere Typen oder für Funktionen, die Dinge zurückgeben, die nicht boolesch sind. Dennoch ist es ein gutes Werkzeug, um (+1) – mgilson

+1

Definitiv einfacher als die Lösung von mgilson zu haben. Dank dafür! Der andere könnte hilfreicher für andere sein, die den Code lesen. Hier, denke ich, könntest du denken, ich hätte einfach 'und' und' &' verwirrt. – j0ker

+0

@mgilson Die 'all'-Funktion war auch die erste Lösung, die mir einfiel (ich würde sie genau aus dem Grund verwenden, den j0ker erwähnt hatte), aber ich entdeckte die Frage zu spät für diese Antwort (+1, btw) :-) – sloth

Verwandte Themen