On Fri, Oct 29, 2021 at 8:11 PM Steven D'Aprano <st...@pearwood.info> wrote:
>
> On Fri, Oct 29, 2021 at 07:17:05PM +1100, Chris Angelico wrote:
>
> > * Argument defaults (either in __defaults__ or __kwdefaults__) are now
> > tuples of (desc, value) or (desc,) for early-bound and late-bound
> > respectively
> > * Early-bound defaults get mapped as normal. Late-bound defaults are
> > left unbound at time of function call.
>
> Pardon me if this has already been discussed, but wouldn't it be better
> to leave defaults and kwdefaults alone, and add a new pair of attributes
> for late bound defaults? `__late_defaults__` and `__late_kwdefaults__`.

The trouble with that is that positional arguments could have any
combination of early and late defaults. If the late ones are in a
separate attribute, there'd need to be some sort of synchronization
between them. (It would work for kwdefaults, but they only apply to
kwonly args - positional-or-keyword args go into __defaults__.)

> Otherwise its a backwards-incompatable change to the internals of the
> function object, and one which is not (so far as I can tell) necessary.
>
> Obviously you need a way to indicate that a value in __defaults__ should
> be skipped. Here's just a sketch. Given:
>
>     def func(a='alpha', b='beta', @c=expression, d=None)
>
> where only c is late bound, you could have:
>
>     __defaults__ = ('alpha', 'beta', None, None)
>     __late_defaults__ = (None, None, <code for expression>, None)
>
> The None values in __defaults__ mean to look in the __late_defaults__
> tuple. If the appropriate value there is also None, return it, otherwise
> the parameter is late-bound. Evaluate it and return the result.

Except that that's still backward-incompatible, since None is a very
common value. So this form of synchronization wouldn't work; in fact,
*by definition*, any object can be in __defaults__, so there's no
possible sentinel that can indicate that late defaults should be
checked. The only way would be to first look in late defaults, and
only then look in defaults... which is basically the same as I have,
only all in a single attribute.

> That means that param=None will be a little bit more costly to fill at
> function call time than it is now, but not by much. And non-None
> defaults won't have any significant extra cost (just one check to see if
> they are None).
>
> And if you really want to keep arg=None as fast as possible, we could
> use some other sentinel like NotImplemented that is much less common.

Having "a bit less" backward incompatibility isn't really a solution;
if we need to have any, why have all the complexity?

> > So far unimplemented is the description of the argument default. My
> > plan is for early-bound defaults to have None there (as they currently
> > do), but late-bound ones get the source code.
>
> That's not what I see currently in 3.10:
>
>     >>> def func(a=1, b=2, c="hello"):
>     ...     pass
>     ...
>     >>> func.__defaults__
>     (1, 2, 'hello')
>
>
> What am I missing?

Currently, you don't get a description, you get a value.

>>> def func(a=0x10, b=16, c=0o20): pass
...
>>> func.__defaults__
(16, 16, 16)

That's not a big deal with early-bound, but it's kinda crucial with
late-bound, since the description is the only thing you'd get.

The spec I'm currently going for is that a description of None means
"use the repr of the value", and that's what early-bound defaults will
use, so that has the same behaviour as current 3.11, and is the way
it's currently implemented in the PEP 671 branch. What needs to change
is late-bound defaults.

Anyway, if someone wants to make changes to the implementation, or
even do up their own from scratch, I would welcome it. It's much
easier to poke holes in an implementation than to actually write one
that is perfect. And fundamentally, there WILL be behavioural changes
here, so I'm not hugely bothered by the fact that the inspect module
needs to change for this.

ChrisA
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/V34GMRHEYBHCESS4G4SRICWEP7LFOHNH/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to