[Python-ideas] Delayed Execution via Keyword

Chris Angelico rosuav at gmail.com
Fri Feb 17 06:21:07 EST 2017

On Fri, Feb 17, 2017 at 10:10 PM, Steven D'Aprano <steve at pearwood.info> wrote:
>> the expression is executed and the delayed
>> expression is replaced with the result. (Thus, the delayed expression is
>> only every evaluated once).
> That's easily done by having the "delayed" keyword cache each expression
> it sees, but that seems like a bad idea to me:
> spam = delayed: get_random_string()
> eggs = delayed: get_random_string()  # the same expression
> spam.upper()  # convert to a real value
> assert spam == eggs  # always true, as they are the same expression
> Worse, suppose module a.py has:
> spam = delayed: calculate(1)
> and module b.py has:
> eggs = delayed: calculate(1)
> where a.calculate and b.calculate do completely different things. The
> result you get will depend on which happens to be evaluated first and
> cached, and would be a nightmare to debug. Truely spooky action-at-a-
> distance code.

My understanding is that a single 'delayed expression' will be
evaluated at most once. It's more like this:

spam = delayed: get_random_string()
eggs = spam

spam.upper() # At this point, the object becomes a real value
assert spam is eggs # always true, as they are the same object

Two instances of "delayed:" will create two distinct delayed expressions.

The big question, though, is what triggers evaluation. AIUI, merely
referencing the object doesn't (so "eggs = spam" won't force
evaluation), but I'm not sure what does.

Do delayed-expressions have identities or only values? For example:

rand = delayed: random.randrange(10)
otherrand = rand
assert rand is otherrand # legal?
randid = id(rand) # legal?
print(rand) # force to concrete value
assert any(rand is x for x in range(10)) # CPython int caching
assert randid == id(rand) # now what?

Alternatively, once the value becomes concrete, the delayed-expression
becomes a trampoline/proxy to the actual value. Its identity remains
unchanged, but all attribute lookups would be passed on to the other
object. That does mean a permanent performance penalty though -
particularly if it's doing it all in Python code rather than some sort
of quick C bouncer.


More information about the Python-ideas mailing list