Short-circuit evaluation like Python's "and" while storing results of checks
<p>I have multiple expensive functions that return results.  I want to return a tuple of the results of all the checks if all the checks succeed.  However, if one check fails I don't want to call the later checks, like the short-circuiting behavior of <code>and</code>.  I could nest <code>if</code> statements, but that will get out of hand if there are a lot of checks.  How can I get the short-circuit behavior of <code>and</code> while also storing the results for later use?</p>

<pre><code>def check_a():
    # do something and return the result,
    # for simplicity, just make it "A"
    return "A"

def check_b():
    # do something and return the result,
    # for simplicity, just make it "B"
    return "B"

...
</code></pre>

<p>This doesn't short-circuit:</p>

<pre><code>a = check_a()
b = check_b()
c = check_c()

if a and b and c:
    return a, b, c
</code></pre>

<p>This is messy if there are many checks:</p>

<pre><code>if a:
   b = check_b()

   if b:
      c = check_c()

      if c:
          return a, b, c
</code></pre>

<p>Is there a shorter way to do this?</p>

<p>Another way to tackle this is using a generator, since generators use lazy evaluation. First put all checks into a generator:</p>

<pre><code>def checks():
    yield check_a()
    yield check_b()
    yield check_c()
</code></pre>

<p>Now you could force evaluation of everything by converting it to a list:</p>

<pre><code>list(checks())
</code></pre>

<p>But the standard all function does proper short cut evaluation on the iterator returned from checks(), and returns whether all elements are truthy:</p>

<pre><code>all(checks())
</code></pre>

<p>Last, if you want the results of succeeding checks up to the failure you can use itertools.takewhile to take the first run of truthy values only. Since the result of takewhile is lazy itself you'll need to convert it to a list to see the result in a REPL:</p>

<pre><code>from itertools import takewhile
takewhile(lambda x: x, checks())
list(takewhile(lambda x: x, checks()))
</code></pre>

python short-circuiting