Short-circuit evaluation like Python's "and" while storing results of checks

Just use a plain old for loop:

results = {}
for function in [check_a, check_b, ...]:
    results[function.__name__] = result = function()
    if not result:
        break

The results will be a mapping of the function name to their return values, and you can do what you want with the values after the loop breaks.

Use an else clause on the for loop if you want special handling for the case where all of the functions have returned truthy results.


Write a function that takes an iterable of functions to run. Call each one and append the result to a list, or return None if the result is False. Either the function will stop calling further checks after one fails, or it will return the results of all the checks.

def all_or_none(checks, *args, **kwargs):
    out = []

    for check in checks:
        rv = check(*args, **kwargs)

        if not rv:
            return None

        out.append(rv)

    return out
rv = all_or_none((check_a, check_b, check_c))

# rv is a list if all checks passed, otherwise None
if rv is not None:
    return rv
def check_a(obj):
    ...

def check_b(obj):
    ...

# pass arguments to each check, useful for writing reusable checks
rv = all_or_none((check_a, check_b), obj=my_object)

In other languages that did have assignments as expressions you would be able to use

if (a = check_a()) and (b = check_b()) and (c = check_c()):

but Python is no such language. Still, we can circumvent the restriction and emulate that behaviour:

result = []
def put(value):
    result.append(value)
    return value

if put(check_a()) and put(check_b()) and put(check_c()):
    # if you need them as variables, you could do
    # (a, b, c) = result
    # but you just want
    return tuple(result)

This might loosen the connection between the variables and function calls a bit too much, so if you want to do lots of separate things with the variables, instead of using the result elements in the order they were put in the list, I would rather avoid this approach. Still, it might be quicker and shorter than some loop.