Re: [Python-ideas] Delayed Execution via Keyword
On 2/19/17, Michel Desmoulinwrote: > Evnetually we also may need to allow this: > > a = lazy stuff > if a is not lazy: > print(a) > > But then lazy can't be used a var name to help with the transition. What about this? if not inspect.islazy(a): print(a) Next idea is probably obvious: class Busy_Beaver: ''' we want to be sure that beaver is disturbed only if it is really necessary ''' def __call_me_later__(self, n): return too_expensive(n) ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Delayed Execution via Keyword
On Sun, Feb 19, 2017 at 10:47 AM, Joseph Hackmanwrote: > Your argument has convinced me, and I now take (what i believe to be) your >> position: >> > > def stuff(arg = lazy f()): > > should result in a function where the default value of arg is not > evaluated until first function call, and then the value of the expression > is used as the default. > Indeed. And in particular, f() *might not* be excuted even during that first (or any) function call, depending on what conditional path are taken within the function body. That's the crucial part. The function may have perfectly good uses where you don't want to take the computational time, or have the side-effects, but other uses where you need that deferred value or action. -- 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. ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Delayed Execution via Keyword
> > This doesn't make sense. Function definition time is very different than > function execution time. Changing that distinction is a WAY bigger change > than I think we should contemplate. > Moreover, there is a completely obvious way to spell the behavior you want: > def stuff(): > arg = f() > # ... whatever ... > This is exactly the obvious way to spell "f() is called every time stuff() > is". I think it would be useful, but yeah, it really doesn't fit in with the rest of lazy/delayed. The present format of defaulting to none and then doing if arg is None: is totally functional. On the flip side, doing a lazy in the function definition would save time evaluating defaults while also fitting in. Your argument has convinced me, and I now take (what i believe to be) your position: def stuff(arg = lazy f()): should result in a function where the default value of arg is not evaluated until first function call, and then the value of the expression is used as the default. Now, back to what Michel was probably actually asking. In the case of: def stuff(arg = lazy []): is the default value of arg a new list with each execution? (i.e. the resulting value of the expression is `make a new list`) I would say that for consistency's sake, not, which I believe would be consistent with the logic behind why default values being [] are kept between calls. a = lazy [] b = a a.append('a') print(b) # expected behavior is ['a'] I maintain that it would be nice for there to be a way to say (the default value of this argument is to run some expression *every time*), but delayed/lazy probably isn't that. On 19 February 2017 at 13:33, David Mertzwrote: > On Sun, Feb 19, 2017 at 10:13 AM, Joseph Hackman > wrote: >> >> My honest preference would be that the [] is evaluated fresh each time >> the function is called. >> def stuff(arg=delayed f()): >> would result in f() being called every time stuff() is. This seems more >> valuable to me than just doing it once when the function is first called. >> > > This doesn't make sense. Function definition time is very different than > function execution time. Changing that distinction is a WAY bigger change > than I think we should contemplate. > > Moreover, there is a completely obvious way to spell the behavior you want: > > def stuff(): > > arg = f() > > # ... whatever ... > > > This is exactly the obvious way to spell "f() is called every time stuff() > is". > > > -- > 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. > ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Delayed Execution via Keyword
On Sun, Feb 19, 2017 at 10:13 AM, Joseph Hackmanwrote: > > My honest preference would be that the [] is evaluated fresh each time the > function is called. > def stuff(arg=delayed f()): > would result in f() being called every time stuff() is. This seems more > valuable to me than just doing it once when the function is first called. > This doesn't make sense. Function definition time is very different than function execution time. Changing that distinction is a WAY bigger change than I think we should contemplate. Moreover, there is a completely obvious way to spell the behavior you want: def stuff(): arg = f() # ... whatever ... This is exactly the obvious way to spell "f() is called every time stuff() is". -- 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. ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Delayed Execution via Keyword
> > One last thing: my vote is not dropping the ":" in front of they > keyword. > > > I think the colon has parser problems, as I showed in some examples. > Plus I don't like how it looks. But I'd much rather have `a = lazy: > stuff` than not have the construct at all, nonetheless. > > This was a typo on my part. I prefer to AVOID the ":" in front of the keyword. ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Delayed Execution via Keyword
On Sun, Feb 19, 2017 at 8:24 AM, Michel Desmoulinwrote: > A great proposal, although now I would have to explain to my students > the subtle difference between: > > res = (print(i * i) for i in range(x)) > res = delayed [print(i * i) for i in range(x)] > They seems doing something similar, but they really don't. Well, at the introductory level they are kinda similar. I know the mechanism would have to be different. But at a first brush it's the difference between delaying the whole concrete collection and delaying one item at a time. That wouldn't be terrible for a first Compsci lesson. > def stuff(arg=delayed []): > > Does this mean we create a NEW list every time in the body function ? Or > just a new one the first time than the reference stays in arg ? > I think this cannot make a new list each time. Of course, I'm one of those people who have used the mutable default deliberately, albeit now it's mostly superseded by functools.lru_cache(). But the idea of a "delayed object" is one that transforms into a concrete (or at least *different* value) on first access. In a sense, the transformation from a delayed object to an iterator is still keeping it lazy; and clearly `x = delayed my_gen()` is a possible pattern. The pattern of `def stuff(arg=delayed expensive_computation(): ...` is important to have. But as in my longer example, `arg` might or might not be accessed in the function body depending on condition execution paths. Still, once `expensive_computation()` happens one time, that should be it, we have a result. Obviously `list()` is not an expensive operation, but the syntax cannot make a boundary for "how costly." > The "delayed" keyword sounds a lot like something used in async io, so I > like "lazy" much more. Not only it is shorter, but it convey the meaning > of what we are doing better. > I like `lazy` too. > a = (await|yield) lazy stuff > a = lazy (await|yield) stuff (should it even allowed ?) > a = (lazy stuff(x) for x in stuff) > a = lazy f'{name}' + stuff(age) # is there a closure where we store "name" > and 'age'? I don't quite have a clear intuition about how lazy/delayed and await/yield/async should interact. I think it would be perfectly consistent with other Python patterns if we decided some combinations cannot be used together. Likewise you can't write `x = await yield from foo`, and that's fine, even though `yield from` is an expression. > First, if there is an exception in the lazy expression, Python must > indicate in the stack trace where this expression has been defined and > where it's evaluated. > Yes. I mentioned that there needs to be *some* way, even if it's an ugly construct, to find out that something is delayed without concretizing it. I think the best idea is hinted at in my preliminary thought. I.e. we can have a special member of a delayed object that does not concretize the object on access. So maybe `object._delayed_code` of something similar. Since it's the interpreter itself, we can say that accessing that member of the object is not a concretization, unlike accessing any other member. Every object that is *not* a delayed/lazy one should probably have None for that value. But delayed ones should have, I guess, the closure that would get executed on access (then once accessed, the object becomes whatever the result of the expression is, with `._delayed_code` then set to None on that transformed object). > a = lazy stuff > if a is not lazy: > print(a) > So my spelling would be: a = lazy stuff if a._delayed_code is not None: print(a) > One last thing: my vote is not dropping the ":" in front of they keyword. > I think the colon has parser problems, as I showed in some examples. Plus I don't like how it looks. But I'd much rather have `a = lazy: stuff` than not have the construct at all, nonetheless. -- 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. ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Delayed Execution via Keyword
A great proposal, although now I would have to explain to my students the subtle difference between: res = (print(i * i) for i in range(x)) print('foo') print(res) And res = delayed [print(i * i) for i in range(x)] print('foo') all(res) They seems doing something similar, but they really don't. Overall, I still love it. When I read about it, I immidiatly though about how Django handles translation in models: - define your string in english - mark it with ugettext_lazy and NOT ugettext - the framework delays the translation until a request comes around with data about the user lang The proposed featured would solve the problem nicely. Although I'm not clear on the result of: def stuff(arg=delayed []): Does this mean we create a NEW list everytime in the body function ? Or just a new one the first time than the reference stays in arg ? Because the first behavior would solve a problem Python had with mutable default arguments since the begining. But that would mean the result of "delayed []" is a concrete thing we store in arg. The "delayed" keyword sounds a lot like something used in async io, so I like "lazy" much more. Not only it is shorter, but it convey the meaning of what we are doing better. Talking about async, we need to be clear on what those do: a = (await|yield) lazy stuff a = lazy (await|yield) stuff (should it even allowed ?) a = (lazy stuff(x) for x in stuff) a = None with open(x) as f: a = lazy stuff() # raise IOError print(a) try: a = lazy stuff() # raise except Exception: pass a = lazy f'{name}' + stuff(age) # is there a closure where we store "name" and 'age'? I can see a reasonable outcome for most of this, but it must be very clear. However, I can see several very important things we need to be taking in consederation debugging wise. First, if there is an exception in the lazy expression, Python must indicate in the stack trace where this expression has been defined and where it's evaluated. Pdb must also be able to allow easily to step in those in a coherent manner. Evnetually we also may need to allow this: a = lazy stuff if a is not lazy: print(a) But then lazy can't be used a var name to help with the transition. One last thing: my vote is not dropping the ":" in front of they keyword. ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Light-weight call-by-name syntax in Python
On Fri, 17 Feb 2017 at 10:23 Stephan Houbenwrote: > Proposal: Light-weight call-by-name syntax in Python > > The following syntax > a : b > is to be interpreted as: > a(lambda: b) > > Effectively, this gives a "light-weight macro system" to Python, > since it allows with little syntax to indicate that the argument to > a function is not to be immediately invoked. > This is, in my view, one case where Python's existing lambda syntax is perfectly sufficient. (I'd even argue it might be the *only* case...) If you could logger.debug(lambda: expensive_to_compute_message_here), I don't think that the delayed-expression proposal would ever have existed. Ed ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/