![](https://secure.gravatar.com/avatar/d67ab5d94c2fed8ab6b727b62dc1b213.jpg?s=120&d=mm&r=g)
On Wed, Oct 27, 2021 at 12:59 PM Chris Angelico <rosuav@gmail.com> wrote:
On Wed, Oct 27, 2021 at 12:50 PM Rob Cliffe <rob.cliffe@btinternet.com> wrote:
On Wed, Oct 27, 2021 at 10:38 AM Rob Cliffe <rob.cliffe@btinternet.com> wrote:
There has been support for evaluating all early-bound defaults before all late-bound defaults. I have been persuaded that this is a reasonable option. AFAICS there would be little practical difference from straight left-to-right evaluation of defaults, since assigning an early-bound default should not have a side effect. So it could even be an implementation choice. If it's an implementation choice, then it'll mean that code is legal on some interpreters and not others. Whether that's a major problem or not I don't know, but generally, when you can't depend on your code working on all interpreters, it's not best practice (eg "open(fn).read()" isn't recommended, even if it happens to close the file promptly in CPython).
ChrisA I guess I wasn't clear. I'm not sure if you understood what I meant to say, or not. First I should have said "binding" rather than "evaluating". What I meant was that in cases like def f(a=earlydefault1, b:= latedefault2, c=earlydefault3, d:=latedefault4): it makes no real difference if the bindings are done in the order a, c, b, d (early ones before late ones) or a, b, c, d (strict left-to-right) since binding an early default should have no side effects, so (I
On 27/10/2021 00:50, Chris Angelico wrote: thought, wrongly) it could be an implementation detail. Of course there IS a difference: it allows late default values to refer to subsequent early default values, e.g. in the example above `latedefault2' could refer to `c`. So yes, then that code would be legal on some interpreters and not others, as you said. If you understood exactly what I meant, I apologise.
Yep, that's precisely the distinction that matters: whether it's legal to refer to parameters further to the right. If we consider tuple unpacking as an approximate parallel:
def f(): a = [10,20,30] i, a[i] = 1, "Hi"
Premature send, oops... def f(): a = [10, 20, 30] i, a[i] = 1, "Hi" print(a) It's perfectly valid to refer to something from earlier in the multiple assignment, because they're assigned left to right. Python doesn't start to look up the name 'a' until it's finished assigning to 'i'. Since Python doesn't really have a concept of statics or calculated constants, we don't really have any parallel, but imagine that we could do this: def f(): # Calculate this at function definition time and then save it # as a constant const pos = random.randrange(3) a = [10, 20, 30] i, a[i] = pos, "Hi" This is something what I'm describing. The exact value of an early-bound argument default gets calculated at definition time and saved; then it gets assigned to its corresponding parameter if one wasn't given. (Actually, I'd really like Python to get something like this, as it'd completely replace the "random=random" optimization - there'd be no need to pollute the function's signature with something that exists solely for the optimization. It'd also make some of these kinds of things a bit easier to explain, since there would be a concept of def-time evaluation separate from the argument list. But we have what we have.) So I think that we did indeed understand one another. ChrisA