On Wed, 22 Jun 2022 at 11:59, David Mertz, Ph.D. <david.me...@gmail.com> wrote: > > Thanks Carl and Chris. After reading your comments, and thinking some more > about it, I agree you are both correct that it only makes sense to have a > DeferredObject act like a closure in the scope of its creation. That really > should suffice for anything I could sensibly want; it's enough for Dask, and > it's enough for functional programming languages with laziness. > > Moreover, the limited laziness that Python currently has also follows that > rule. I also haven't gotten to writing that needed section of the PEP, but I > need to address generators and boolean shortcutting as limited kinds of > laziness. Obviously, my PEP is much broader than those, but generators also > use lexical scope not dynamic scope. > >>> Possibly in my defense, I think Carl's PEP 690 can do the same thing. :-) >> >> >> I’m not sure what you mean. I don’t think there’s any way PEP 690 can >> introduce dynamic scoping like this. Can you give an example? > > > Let me just withdraw that. I think I might be able to construct something > where a module's top-level code does something perverse with the call stack > where it winds up getting evaluated that can act like dynamic scoping. I > might be wrong about that; but even if it's technically true, it would need > very abnormal abuse of the language (as bad as the lovely zero-argument > super() does :-)). >
So then a deferred object is basically a lambda function that calls itself when referenced. That's reasonable, and broadly sane... > I don't think this actually has much effect on encompassing late-binding of > default arguments, other than needing to say the arguments contribute to the > scope on a left-to-right basis. But actually, despite writing the section > because of recent discussion, PEP-671 has little to do with why I want > generalized deferreds. I've suggested it on a number of occasions long > before PEP-671 existed (but admittedly always as a passing thought, not as a > detailed proposal... which my draft still is not either). > > On one small point Chris mentions, I realized before he commented that there > was no need to actually rebind the deferred argument to force evaluation of > its default. Simply mentioning it would force the evaluation. I found > something similar in PEP-690 that reminded me that doing this is plenty: > > def func(items=[], n=later len(items)): > n # Evaluate the Deferred > items.append("Hello") > print(n) > > Of course, that's an extra first line of the function for the motivating case > of emulating the sentinel pattern. But it also does let us *decide* when > each deferred gets "fixed in place". I.e. maybe a, b, and c are all `later` > arguments. We could make the first line `a, b` but only reference `c` at > some later point where it was appropriate to the logic we wanted. > ... but it doesn't work for this case. If a deferred is defined by its creation context, then the names 'len' and 'items' will be looked up in the surrounding scope, NOT the function's. It would be like this: def func(items=[], n=lambda: len(items)): n = n() which, in turn, is similar to this: _default = lambda: len(items) def func(items=[], n=None): if n is None: n = _default n = n() and it's fairly clear that this has the wrong scope. That's why PEP 671 has the distinction that the late-bound default is scoped within the function body, not its definition. Otherwise, this doesn't work. ChrisA _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/3VQ4DOILYKKI47AS2EELGHAAI7WPS3B5/ Code of Conduct: http://python.org/psf/codeofconduct/