On Fri, Oct 29, 2021 at 11:22:29AM +0200, Gerrit Holl wrote:
> On Fri, 29 Oct 2021 at 11:10, Steven D'Aprano <st...@pearwood.info> wrote:
> > 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)
> 
> Why not define an object for that?

Because then it would have to be a public, named builtin. Or at least a 
public, named value, even if it's not in the builtin namespace, it would 
still be accessible to coders just by introspecting the function object.

I think NotImplemented is a good sentinel to use. Its the same size as 
None, and much less commonly used as a default value.

So the algorithm for fitting default values to parameters might look 
like this pseudocode:

    # single pass version
    for parameter in parameters:
        if parameter is unbound:
            obj = get default for this parameter, or fail
            if obj is NotImplemented:
                obj = get late_bound default for this parameter, or fail
                if obj is not NotImplemented:
                    obj = (eval obj in function namespace)
            bind obj to parameter


    # two pass version, that ensures all early-bound parameters
    # have a value before the late-bound ones are evaluated
    for parameter in parameters:
        if parameter is unbound:
            obj = get default for this parameter, or fail
            if obj is NotImplemented:
                continue
            bind obj to parameter
    for parameter in parameters:
        if parameter is unbound:
            obj = get late_bound default for this parameter, or fail
            if obj is not NotImplemented:
                obj = (eval obj in function namespace)
            bind obj to parameter



> In this example I don't mean a fancy new delayed evaluation type such
> as has been discussed elsewhere, but just a sentinel so Python knows
> it has to look into __late_defaults__ at all (I'm probably missing
> something, and I didn't read all prior emails on this, but why
> wouldn't this type contain a reference to the code object directly,
> negating the need for __late_defaults__...?).

How would the interpreter tell the difference between a code object 
which is early bound and needs to be returned directly, unexecuted, and 
a code object which is late-bound and needs to be executed?

Any code object inside the function defaults can be grabbed and used as 
an early default, and we'd want it to remain unevaluated.



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

Reply via email to