On Fri, Dec 3, 2021 at 2:17 AM Steven D'Aprano <steve@pearwood.info> wrote:
On Wed, Dec 01, 2021 at 09:58:11PM -0600, Abe Dillon wrote:
My favorite alternative is ?= if people think => and -> are getting overly loaded. What I really don't like is @param=[] because it puts the emphasis on the parameter name rather than the act of binding. Not only does it make it look like @param is a special kind of variable, it also mimics the *args and **kwargs syntax which makes them seem related.
But it *is* a special kind of parameter: it is a parameter that uses late binding for the default value, instead of early binding.
Putting the emphasis on the parameter name is entirely appropriate.
Late bound parameters don't have a different sort of binding to other parameters. There aren't two kinds of binding:
1. Parameters with no default, and parameters with early bound default, use the same old type of name binding that other local variables use (local slots in CPython, maybe a dict for other implementations);
2. and parameters with late bound defaults use a different sort of name binding, and we need a different syntax to reflect that.
That is wrong: there is only one sort of binding in Python (although it can have a few different storage mechanisms: slots, cells and dict namespaces, maybe even others). The storage mechanism is irrelevant. It's all just name binding, and the implementation details are handled by the interpreter.
In these examples, is the name binding any different? x = 1 x += 1 (x := 1) for x in [1]: pass They use different equals signs, but once the assignment happens, it's the exact same name binding. But exactly what IS different about them? Is the name 'x' different? The value 1? The name binding itself?
By the time the function body is entered, all the parameters have been bound to a value. (If there are parameters that don't have a value, the interpreter raises an exception and you never enter the function body.) It doesn't matter where those values came from, whether they were passed in by the caller, or early bound defaults loaded from the cache, or late bound defaults freshly evaluated. The value is bound to the parameter in exactly the same way, and you cannot determine where that value came from.
Yes, that is correct. And the parameter is the exact same kind of thing either way, too, so adorning the parameter name is wrong too. And the expression being evaluated is still just an expression, so adorning THAT is wrong too. There's nothing about late-bound defaults that is fundamentally different from the rest of Python, so there's no obvious "this is the bit to adorn" thing. In contrast, *args and **kwargs actually change the parameter that gets received: one gives a sequence, the other a mapping, whereas leaving off both markers gives you a single value. ChrisA