On 2021-12-08 20:55, Chris Angelico wrote:
(H) This is true. But if the two syntaxes can be sufficiently similar, the cost should be low, and the feature benefit would be high. Early binding lets you "def f(x=x):" in a loop and capture each x as it goes by. Late binding lets you "def f(x=>):" and get a new list every time. Both have their places.
(The "two syntaxes" here is referring to syntaxes for early and late binding.) I'm actually worried about the reverse. When the two syntaxes are similar, it will be easier to mistake one for the other.
(D) The (late-binding) default value should be a first-class object that can be accessed and manipulated.
Eric V.Smith: [AFAIU, paraphrased] I want the default value to be an object that I can inspect and change. David Mertz: "For the reasons Eric Smith and others have pointed out, I really WANT to keep inspectability of function signatures." Stephen J. Turnbull: "More than any of these issues, the lack of a well-defined, properly introspectable object bothers me."
Chris A gave a reply including 'If you consider the equivalent to be a line of code in the function body, then the signature has become MASSIVELY more useful. Instead of simply seeing "x=<object object at 0x7fba1b318690>", you can see "x=>" and be able to see what the value would be.'
Correct. In general, expressions are not first-class objects in Python; they only become them when turned into functions or classes (including the special functions used by genexps/comps). We do not have an introspectable, externally-testable, first-class object to represent any other expression:
x = 1/y if y else "invalid"
There's no object for "1/y". Trying to create one would be a nightmare of subtleties, where assignment expressions would break things, nonlocal variable references would become tricky, etc, etc. Similarly:
As I have stated repeatedly, ternary expressions are not parallel because they do not have a distinct definition-time and call-time. Please stop bringing up the ternary operator case and pretending it is the same as a function. It is not, for reasons that I have already explained several times.
To try stating this in yet another way, currently if I have:
def f(a=<some code here>)
<some code here> must be something that evaluates to a first-class object, and the "argument default" IS that first-class object --- not bytecode to generate it, not some behavior that evaluates the expression, no, the default value is itself an object. This would not be the case for late-bound defaults under the PEP. (Rather, as I phrased it in another post, there would not "be" a late-bound default at all; there would just be some behavior in the function to do some stuff when that argument isn't passed.)