On Wed, 22 Jun 2022 at 11:59, David Mertz, Ph.D. <[email protected]> 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 -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at
https://mail.python.org/archives/list/[email protected]/message/3VQ4DOILYKKI47AS2EELGHAAI7WPS3B5/
Code of Conduct: http://python.org/psf/codeofconduct/