Request for comments: use-cases for delayed evaluation

Steven D'Aprano steve+comp.lang.python at pearwood.info
Thu May 17 10:13:06 EDT 2018


Suppose Python had a mechanism to delay the evaluation of expressions 
until needed. What would you use it for?

Python already does this on an ad hoc basis. For example, the "and" and 
"or" operators are special:

    <left expression> and <right expression>

If the expression on the left is falsey, the expression on the right is 
ignored and not evaluated. Similarly for "or":

    <left expression> or <right expression>

only evaluates the expression on the right if the one on the left is 
falsey.

Similarly for ternary if.

But apart from these few ad hoc examples of short-circuiting behaviour, 
we don't really have an convenient way to do the same in our code. But 
what if we did? I can think of four places where I would like to delay 
the evaluation of expressions:

1. Late binding of function parameter defaults.

Given a function with defaults:

    def function(arg=DEFAULT)

Python's standard behaviour is to evaluate DEFAULT *once*, then always 
return the same value. Sometimes we want the default to be re-evaluated 
each time the function is called without an argument.


2. Printing of individual expressions, not just their value, within a 
line of code.

Sometimes I have a line of code where I'm not sure if a particular sub-
expression is correct. Of course I can refactor the code, but a 
lightweight solution would be to just insert a print:

    result = spam + eggs + print(EXPRESSION) +  cheese

Alas, this doesn't work: print doesn't return anything useful (it returns 
None), and the expression is evaluated before print can see it. But a 
simple helper function could solve this problem:

    # pseudo-code
    def debugprint(EXPRESSION):
        value = (evaluate EXPRESSION)
        print(EXPRESSION AS A STRING, value)
        return value



3. Assertions, similar to the "assert" statement, which don't evaluate 
the (potentially expensive) expression unless a flag is switched on:

    # pseudo-code
    def myassert(EXPRESSION, flag=None):
        if flag is None:
            flag = DEBUGGING
        if flag and not (evaluate EXPRESSION):
            s = EXPRESSION as a string
            raise AssertionError('assertion "%s" failed' % s)



4. Similarly, delaying the evaluation of expressions for logging:

    log.debug(str(sum(primes_below(10**10)))

has to calculate a huge number of prime numbers, and sum them, even if 
the log level is above DEBUG and the result won't be logged.


Of course I realise that every one of these have work-arounds or 
alternate solutions, some of which work quite well, some of which not so 
well. That's not my question.

My question is, if we had a way to delay the evaluation of expressions, 
what if anything would you use it for?

Use-cases beyond the four above are especially welcome.



-- 
Steve




More information about the Python-list mailing list