[Python-ideas] Delayed Execution via Keyword
josephhackman at gmail.com
Fri Feb 17 10:12:12 EST 2017
A few points for clarity:
Yes, I would expect each instance of delayed to result in a new delayed expression, without caching, except for multiple calls to that same delayed expression instance.
Also, I suggested the colon : because unlike async/await, the following expression is NOT executed at the time delayed is executed. The only other ways to do this on Python I know of are def and lambda, both of which use colons to highlight this.
As for what triggers execution? I think everything except being on the right side of an assignment. Even identity. So if a delayed expression would evaluate to None, then code that checks is None should return true. I think this is important to ensure that no code needs to be changed to support this feature.
So for Chris: yes, rand is otherrand not because the delayed instances are the same, but because the value under them is the same, and the is should trigger evaluation. Otherwise code would need to be delayed aware.
Finally as for the word delayed. Yes, it could be a symbol, or existing keyword, but I have no suggestions on that front.
> On Feb 17, 2017, at 6:21 AM, Chris Angelico <rosuav at gmail.com> wrote:
> 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.
> Python-ideas mailing list
> Python-ideas at python.org
> Code of Conduct: http://python.org/psf/codeofconduct/
More information about the Python-ideas