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__`.

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.

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.

The advantage is that code that inspects function objects but doesn't 
know anything about late-binding will still work, except that it will 
report late-bound parameters as if they were set to None.

Anyway, I care less about the implementation and more about not breaking 
backwards compatibility when it comes to inpecting function objects.


> 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?


-- 
Steve
_______________________________________________
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/DM5W3REWVUWI7XKCN5UCA7UL27YABTOI/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to