[Python-ideas] Delayed Execution via Keyword
David Mertz
mertz at gnosis.cx
Fri Feb 17 01:55:40 EST 2017
On Thu, Feb 16, 2017 at 10:33 PM, Joshua Morton <joshua.morton13 at gmail.com>
wrote:
> David, can you elaborate on your example?
>
> if we replaced line four with
>
> >>> x = my_lazy_func(b, delayed c)
>
> what would the value of `x` be, and how would this differ from either
>
The value of the function would be whatever you want, including another
delayed object, potentially.
Here's a toy function just to show the pattern I have in mind:
def my_lazy_func(x, y):
if x == 0:
# evaluate y if it was lazy, or just return plain value
return y
elif x > 0:
# create a lazy object whether y was lazy or concrete
# if y *was* lazy, it remains so in delayed expression
return delayed y + 17
elif x < -10:
# evaluate y, if delayed, by virtue of being part of
# plain non-delayed RHS expression
z = y * 6
return z
else:
# y never mentioned, so if it was lazy nothing changes
return x - 22
Whether or not 'c' (called 'y' within the function scope) gets
evaluated/computed depends on which branch was taken within the function.
Once the delayed computation is done, the object at the delayed address
becomes concrete thereafter to avoid repeated (and potentially stateful or
side-effect causing evaluation).
One question is whether you'd need to write:
m = delayed 1 + 2
n = delayed m * 3
# This seems ugly and unnecessary (but should work)
q = delayed m / delayed n
# This seems better (does not evaluate m or n)
# everything lazy within delayed expression stays unevaluated
q2 = delayed m/n
If you ever need to explicitly evaluate a delayed object, it is as simple
as putting a name pointing to it on a line by itself:
f = delayed 1 + 2
# We want to evaluate f before next op for some reason
f
# f is already a concrete value now, before calculating g
g = f * 7
So for example, in a hypothetical Python 3.7+:
>>
>> >>> a = delayed 1 + 2
>>
>> >>> b = delayed b * 3
>>
>> >>> c = delayed 12/3
>>
>> >>> my_lazy_func(b, delayed c) # evaluates b but not yet c
>> >>> b
>> 9
>> >>> delayed c
>> <delayed object at 0x123456789>
>>
>>
>> If you want to do something like Dask... or for Dask itself to be able to
>> use it in some eventual version, you'd need to be able to keep objects from
>> evaluating even while you passed them around. The obvious use is for
>> finding parallelism, but other things like passing callbacks might find
>> this useful too.
>>
>> Dask delayed objects stay lazy until you explicitly `.compute()` on them
>> (which does so recursively on every lazy object that might go into the
>> computation). This hypothetical new keyword would have object evaluate
>> eagerly *unless* you explicitly kept them lazy. But the idea is that
>> the programmer would still get to decide in their code.
>>
>>
>> On Feb 16, 2017 9:53 PM, "Joseph Jevnik" <joejev at gmail.com> wrote:
>>
>> You might be interested in https://github.com/llllllllll/lazy_python,
>> which implements the features you describe but instead of a keyword it uses
>> a decorator.
>>
>> On Fri, Feb 17, 2017 at 12:24 AM, Joseph Hackman <josephhackman at gmail.com
>> > wrote:
>>
>> Howdy All!
>>
>> This suggestion is inspired by the question on "Efficient debug logging".
>>
>>
>> I propose a keyword to mark an expression for delayed/lazy execution, for
>> the purposes of standardizing such behavior across the language.
>>
>> The proposed format is:
>> delayed: <expr>
>> i.e. log.info("info is %s", delayed: expensiveFunction())
>>
>> Unlike 'lambda' which returns a function (so the receiver must be
>> lambda-aware), delayed execution blocks are for all purposes values. The
>> first time the value (rather than location) is read, or any method on the
>> delayed object is called, the expression is executed and the delayed
>> expression is replaced with the result. (Thus, the delayed expression is
>> only every evaluated once).
>>
>> Ideally:
>> a = delayed: 1+2
>> b = a
>> print(a) #adds 1 and 2, prints 3
>> # a and b are now both just 3
>> print(b) #just prints 3
>>
>> Mechanically, this would be similar to the following:
>>
>> class Delayed():
>> def __init__(self, func):
>> self.__func = func
>> self.__executed = False
>> self.__value = None
>>
>> def __str__(self):
>> if self.__executed:
>> return self.__value.__str__()
>> self.__value = self.__func()
>> self.__executed = True
>> return self.__value.__str__()
>>
>>
>> def function_print(value):
>> print('function_print')
>> print(value)
>>
>> def function_return_stuff(value):
>> print('function_return_stuff')
>> return value
>>
>> function_print(function_return_stuff('no_delay'))
>>
>> function_print(Delayed(lambda: function_return_stuff('delayed')))
>>
>> delayed = Delayed(lambda: function_return_stuff('delayed_object'))
>> function_print(delayed)
>> function_print(delayed)
>>
>> Unfortunately, due to https://docs.python.org/3/reference/datamodel.html#
>> special-lookup , this magic delayed class would need to implement many
>> magic methods, as __getattribute__ is not _always_ called.
>>
>> _______________________________________________
>> Python-ideas mailing list
>> Python-ideas at python.org
>> https://mail.python.org/mailman/listinfo/python-ideas
>> Code of Conduct: http://python.org/psf/codeofconduct/
>>
>>
>>
>> _______________________________________________
>> Python-ideas mailing list
>> Python-ideas at python.org
>> https://mail.python.org/mailman/listinfo/python-ideas
>> Code of Conduct: http://python.org/psf/codeofconduct/
>>
>> _______________________________________________
>> Python-ideas mailing list
>> Python-ideas at python.org
>> https://mail.python.org/mailman/listinfo/python-ideas
>> Code of Conduct: http://python.org/psf/codeofconduct/
>
>
--
Keeping medicines from the bloodstreams of the sick; food
from the bellies of the hungry; books from the hands of the
uneducated; technology from the underdeveloped; and putting
advocates of freedom in prisons. Intellectual property is
to the 21st century what the slave trade was to the 16th.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20170216/d3e1f2e4/attachment-0001.html>
More information about the Python-ideas
mailing list