On Mon, May 25, 2020 at 06:22:14PM +0200, Dominik Vilsmeier wrote:
> It wouldn't copy the provided default, it would just reevaluate the
> expression. Python has already a way of deferring evaluation, generator
> expressions:
>
> >>> x = 1
> >>> g = (x for __ in range(2))
> >>> next(g)
> 1
> >>> x = 2
> >>> next(g)
> 2
A function would be a more obvious mechanism. But this won't work to
solve the mutable default problem. Here's a simulation:
# we want to delay evaluation for arg=x
# in this case we have arg=[]
x = []
g = lambda: x
def func():
arg = g()
return arg
At first it seems to work:
py> func()
[]
py> func()
[]
But we have the same problem with mutable defaults:
py> L = func()
py> L.append(1)
py> func()
[1]
The problem is that this model just reuses the object referenced in x.
That's early binding!
Python functions don't use a hidden function or generator `g`, as in
this simulation, or a global variable `x`. They stash the default value
inside the function object, in a dunder attribute, and then retrieve it
when needed.
To get late binding, you need to stash not the *value* of x, in this
example an empty list `[]`, but some sort of code which will create a
new empty list each time. A naive implementation might stash the source
code expression and literally evaluate it:
x = '[]'
g = lambda: eval(x)
but there are probably faster ways:
x = '[]'
g = eval('lambda: %s' % (x,))
One way or the other, late binding has to re-evaluate the expression for
the default value. Whether it uses the actual source code, or some
clever byte-code, it has to recalculate that value each time, not just
retrieve it from somewhere it was stashed.
--
Steven
_______________________________________________
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/7RNYPBKZROD7CE4WPJFZTNDGSJD247TP/
Code of Conduct: http://python.org/psf/codeofconduct/