On Fri, Dec 3, 2021 at 1:53 AM Steven D'Aprano firstname.lastname@example.org wrote:
On Thu, Dec 02, 2021 at 11:00:33PM +1100, Chris Angelico wrote:
On Thu, Dec 2, 2021 at 8:40 PM Steven D'Aprano email@example.com wrote:
Depending on the implementation, you *might* be able to inspect the function and see the default expression as some sort of callable function, or evaluatable code object. (That would be nice.)
Unfortunately not, since the default expression could refer to other parameters, or closure variables, or anything else from the context of the called function. So you won't be able to externally evaluate it.
Why not? Functions can do all those things: refer to other variables, or closures, or anything else. You can call functions. Are you sure that this limitation of the default expression is not just a limitation of your implementation?
def f(): a = 1 def f(b, c=>a+b): return c a = 2 return f
If there were a function to represent the late-bound default value for c, what parameters should it accept? How would you externally evaluate this? And also: what do you gain by it being a function, other than a lot of unnecessary overhead?
And it is potentially a LOT of unnecessary overhead. Consider this edge case:
def f(a, b=>c:=len(a)): ...
In what context should the name c be bound? If there's a function for the evaluation of b, then that implies making c a closure cell, just for the sake of that. Every reference to c anywhere in the function (not just where it's set to len(a), but anywhere in f()) has to dereference that.
It's a massive amount of completely unnecessary overhead AND a difficult question of which parts belong in the closure and which parts belong as parameters, which means that this is nearly impossible to define usefully.
I'm still unsure whether this is a cool feature or an utter abomination:
... try: print("You passed x as", x) ... except UnboundLocalError: print("You didn't pass x") ...
f.__defaults_extra__ = ("n/a",) f(42)
You passed x as 42
You didn't pass x
That is absolutely an abomination. If your implementation has the side-effect that setting a regular early-bound default to Ellipsis makes the parameter unable to retrieve the default, then the implementation is fatally broken.
It absolutely is not a feature.
That's not what the example shows. It shows that changing dunder attributes can do this. I'm not sure why you think that the implementation is as restricted as you imply. The assignment to __defaults_extra__ is kinda significant here :)