<div dir="ltr"><div dir="auto">Dask also has a function delayed() that may be used as an decorator and in other ways like:<div dir="auto"><br></div></div><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div dir="auto"><div><font face="monospace, monospace">>>> from dask import delayed</font></div></div></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div dir="auto"><div><font face="monospace, monospace">>>> from operator import add, mul</font></div><div><font face="monospace, monospace">>>> a = delayed(add)(1, 2)</font></div><div><font face="monospace, monospace">>>> b = delayed(mul)(a, 3)</font></div></div></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div dir="auto"><div><font face="monospace, monospace">>>> b</font></div><div><font face="monospace, monospace">Delayed('mul-1907f29b-60a4-48af-ba2a-938556555f9b')<br></font></div></div></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div dir="auto"><div><font face="monospace, monospace">>>> c = b.compute()</font></div></div></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div dir="auto"><div><font face="monospace, monospace">>>> c</font></div><div><font face="monospace, monospace">9</font></div></div></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div dir="auto"><div><font face="monospace, monospace">>>> b.dask</font></div><div><font face="monospace, monospace"><div>{'add-d49ba000-dd5d-4031-8c37-6514626a3d81': (<function _operator.add>, 1, 2),</div><div> 'mul-1907f29b-60a4-48af-ba2a-938556555f9b': (<function _operator.mul>,</div><div>  'add-d49ba000-dd5d-4031-8c37-6514626a3d81',</div><div>  3)}</div></font></div></div></blockquote><div style="font-family:monospace,monospace"><font face="monospace, monospace"><br></font></div><font face="arial, helvetica, sans-serif">You <b>can</b> do pretty much anything you'd want to using this approach... including the real job of Dask, to identify latent parallelism and execute computations on many cores or many machines in a cluster.</font><div><font face="arial, helvetica, sans-serif"><br></font></div><div><font face="arial, helvetica, sans-serif">But actual syntax to do all of this would be really elegant.  I think for this to be as useful as I'd want, you'd sometimes need to be to continue delaying computation rather than doing so on every access  I guess as syntax, the `delayed:` construct would work (I think having no colon would more closely model `yield` and `yield from` and `await` and `async` which this is kinda-sorta akin to).</font></div><div><font face="arial, helvetica, sans-serif"><br></font></div><div><font face="arial, helvetica, sans-serif">So for example, in a hypothetical Python 3.7+:</font></div><div><font face="arial, helvetica, sans-serif"><br></font></div><blockquote style="margin:0 0 0 40px;border:none;padding:0px"><div><font face="arial, helvetica, sans-serif">>>> a = delayed 1 + 2</font></div></blockquote><blockquote style="margin:0 0 0 40px;border:none;padding:0px"><div><font face="arial, helvetica, sans-serif">>>> b = delayed b * 3</font></div></blockquote><blockquote style="margin:0 0 0 40px;border:none;padding:0px"><div><font face="arial, helvetica, sans-serif">>>> c = delayed 12/3</font></div></blockquote><blockquote style="margin:0 0 0 40px;border:none;padding:0px"><font face="arial, helvetica, sans-serif">>>> my_lazy_func(b, delayed c) # evaluates b but not yet c<br>>>> b<br>9<br>>>> delayed c<br><delayed object at 0x123456789></font></blockquote><div><font face="monospace, monospace"><br></font></div><div><font face="arial, helvetica, sans-serif">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.</font></div><div><font face="arial, helvetica, sans-serif"><br></font></div><div><font face="arial, helvetica, sans-serif">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 <b>unless</b> you explicitly kept them lazy.  But the idea is that the programmer would still get to decide in their code.<br></font><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div dir="auto"><div><font face="monospace, monospace"><br></font></div></div></blockquote><div class="gmail_extra"><div class="gmail_quote">On Feb 16, 2017 9:53 PM, "Joseph Jevnik" <<a href="mailto:joejev@gmail.com" target="_blank">joejev@gmail.com</a>> wrote:<br type="attribution"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">You might be interested in <a href="https://github.com/llllllllll/lazy_python" target="_blank">https://github.com/llllllllll/<wbr>lazy_python</a>, which implements the features you describe but instead of a keyword it uses a decorator.<br></div><div class="gmail_extra"><br><div class="gmail_quote">On Fri, Feb 17, 2017 at 12:24 AM, Joseph Hackman <span dir="ltr"><<a href="mailto:josephhackman@gmail.com" target="_blank">josephhackman@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">Howdy All!<div><br></div><div>This suggestion is inspired by the question on "Efficient debug logging".</div><div> <br></div></div></blockquote></div></div></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div></div><div>I propose a keyword to mark an expression for delayed/lazy execution, for the purposes of standardizing such behavior across the language.</div><div><br></div><div>The proposed format is:<br>delayed: <expr></div><div>i.e. <a href="http://log.info" target="_blank">log.info</a>("info is %s", delayed: expensiveFunction())</div><div><br></div><div>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).</div><div><br></div><div>Ideally:</div><div>a = delayed: 1+2</div><div>b = a</div><div>print(a) #adds 1 and 2, prints 3</div><div># a and b are now both just 3</div><div>print(b) #just prints 3</div><div><br></div><div>Mechanically, this would be similar to the following:</div><div><pre style="background-color:rgb(43,43,43);color:rgb(169,183,198);font-family:"courier new";font-size:9pt"><span style="color:rgb(204,120,50);font-weight:bold">class </span><span style="font-weight:bold">Delayed</span>():<br>    <span style="color:rgb(204,120,50);font-weight:bold">def </span><span style="color:rgb(178,0,178)">__init__</span>(<span style="color:rgb(148,85,141)">self</span><span style="color:rgb(204,120,50)">, </span>func):<br>        <span style="color:rgb(148,85,141)">self</span>.__func = func<br>        <span style="color:rgb(148,85,141)">self</span>.__executed = <span style="color:rgb(204,120,50);font-weight:bold">False<br></span><span style="color:rgb(204,120,50);font-weight:bold">        </span><span style="color:rgb(148,85,141)">self</span>.__value = <span style="color:rgb(204,120,50);font-weight:bold">None<br></span><span style="color:rgb(204,120,50);font-weight:bold"><br></span><span style="color:rgb(204,120,50);font-weight:bold">    def </span><span style="color:rgb(178,0,178)">__str__</span>(<span style="color:rgb(148,85,141)">self</span>):<br>        <span style="color:rgb(204,120,50);font-weight:bold">if </span><span style="color:rgb(148,85,141)">self</span>.__executed:<br>            <span style="color:rgb(204,120,50);font-weight:bold">return </span><span style="color:rgb(148,85,141)">self</span>.__value.<span style="color:rgb(178,0,178)">__str__</span>()<br>        <span style="color:rgb(148,85,141)">self</span>.__value = <span style="color:rgb(148,85,141)">self</span>.__func()<br>        <span style="color:rgb(148,85,141)">self</span>.__executed = <span style="color:rgb(204,120,50);font-weight:bold">True<br></span><span style="color:rgb(204,120,50);font-weight:bold">        return </span><span style="color:rgb(148,85,141)">self</span>.__value.<span style="color:rgb(178,0,178)">__str__</span>()<br><br><br><span style="color:rgb(204,120,50);font-weight:bold">def </span><span style="font-weight:bold">function_print</span>(value):<br>    <span style="color:rgb(136,136,198)">print</span>(<span style="color:rgb(0,128,128)">'function_print'</span>)<br>    <span style="color:rgb(136,136,198)">print</span>(value)<br><br><span style="color:rgb(204,120,50);font-weight:bold">def </span><span style="font-weight:bold">function_return_stuff</span>(value):<br>    <span style="color:rgb(136,136,198)">print</span>(<span style="color:rgb(0,128,128)">'function_return_stuff'</span>)<br>    <span style="color:rgb(204,120,50);font-weight:bold">return </span>value<br><br>function_print(function_return<wbr>_stuff(<span style="color:rgb(0,128,128)">'no_delay'</span>))<br><br>function_print(Delayed(<span style="color:rgb(204,120,50);font-weight:bold">lambda</span>: function_return_stuff(<span style="color:rgb(0,128,128)">'delayed<wbr>'</span>)))<br><br>delayed = Delayed(<span style="color:rgb(204,120,50);font-weight:bold">lambda</span>: function_return_stuff(<span style="color:rgb(0,128,128)">'delayed<wbr>_object'</span>))<br>function_print(delayed)<br>function_print(delayed)</pre></div><div>Unfortunately, due to <a href="https://docs.python.org/3/reference/datamodel.html#special-lookup" target="_blank">https://docs.python.org/3/r<wbr>eference/datamodel.html#specia<wbr>l-lookup</a> , this magic delayed class would need to implement many magic methods, as __getattribute__ is not _always_ called.</div></div>
<br>______________________________<wbr>_________________<br>
Python-ideas mailing list<br>
<a href="mailto:Python-ideas@python.org" target="_blank">Python-ideas@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/python-ideas" rel="noreferrer" target="_blank">https://mail.python.org/mailma<wbr>n/listinfo/python-ideas</a><br>
Code of Conduct: <a href="http://python.org/psf/codeofconduct/" rel="noreferrer" target="_blank">http://python.org/psf/codeofco<wbr>nduct/</a><br></blockquote></div><br></div>
<br>______________________________<wbr>_________________<br>
Python-ideas mailing list<br>
<a href="mailto:Python-ideas@python.org" target="_blank">Python-ideas@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/python-ideas" rel="noreferrer" target="_blank">https://mail.python.org/mailma<wbr>n/listinfo/python-ideas</a><br>
Code of Conduct: <a href="http://python.org/psf/codeofconduct/" rel="noreferrer" target="_blank">http://python.org/psf/codeofco<wbr>nduct/</a><br></blockquote></div></div>
</div></div>