
On Sun, Oct 31, 2021 at 4:37 PM Steven D'Aprano <steve@pearwood.info> wrote:
On Sun, Oct 31, 2021 at 02:56:36PM +1100, Chris Angelico wrote:
Current versions of the PEP do not use the term "default value" when referring to late binding (or at least, if I've made a mistake there, then please point it out so I can fix it). I'm using the term "default expression", or just "default" (to cover both values and expressions).
I was just thinking of suggesting that to you, so I'm glad to see you're much faster on the uptake than I am!
Of course all parameters are syntactically an expression, including now:
# the status quo def func(arg=CONFIG.get('key', NULL)):
The default expression is evaluated at function definition time, and the result of that (an object, a.k.a. a value) is cached in the function object for later use. With late-binding:
def func(@arg=CONFIG.get('key', NULL)):
the expression is stashed away somewhere (implementation details), in some form (source code? byte-code? an AST?) rather than immediately evaluated. At function call time, the expression is evaluated, and the result (an object, a.k.a. a value) is bound to the parameter.
The code for it is part of the byte-code, and I'm planning to have either the source code or the AST (or a reconstituted source code) stored for documentation purposes. This, in fact, is true at compilation time regardless of whether it's early-bound or late-bound. Consider: def make_func(): def func(arg=CONFIG.get('key', NULL)): ... Is the expression for this default argument value "stashed away" somewhere? Well, kinda, I guess. It's part of the code that the 'def' statement produces, and will be run when make_func() runs. The difference is that here: def make_func(): def func(arg=>CONFIG.get('key', NULL)): ... the code is part of func, rather than make_func. So you're absolutely right: either way, the default is an expression. I'm using the term "default expression" to mean that the expression is evaluated at call time rather than def time, but I'm open to other terminology.
In neither case is it correct to say that the default value of arg is the *expression* `CONFIG.get('key', NULL)`, it is in both the early and late bound cases the *result* of *using* (evaluating) the expression to generate a value.
https://en.wikipedia.org/wiki/Use%E2%80%93mention_distinction
I'm fairly confident that everyone understands that:
"the default value is CONFIG.get('key', NULL)"
is shorthand for the tediously long and pedantic explanation that it's not the expression itself that is the default value, but the result of evaluating the expression. Just like we understand it here:
if arg is None: arg = CONFIG.get('key', NULL)
The only difference is when the expression is evaluated.
Exactly. ChrisA