That's a problem I've also encountered countless times.

But the solution you propose only covers the use cases where we always pass the arguments. If your main function looks like the following, you wouldn't be able to set them as deferred:

def main_function(action, a=2, b=3):
    if action == "product":
        return a * b

    if action == "complicated_action":
        return complicated_action(a=a, b=b)

    ...

Maybe we could make deferred a keywork (only in this context), like this:

def main_function(action, deferred a=2, deferred b=3):
    if action == "product":
        return a * b  # will return 6

    if action == "complicated_action":
        return complicated_action(a=a, b=b)  # will return the same as complicated_action()

    ...


deferred variables would just be classic variables some 'deferred' flag, which when they are passed to a function with a default value, are redefined to that value.
And probably, when we use them (read them or assign a new value to them), they would lose this deferred flag.


Le 20/07/2018 à 11:03, Peter O'Connor a écrit :
Often when programming I run into a situation where it would be nice to have "deferred defaults".  Here is an example of what I mean: 
    
    def subfunction_1(a=2, b=3, c=4):
        return a+b*c

    def subfunction_2(d=5, e=6, f=7):
        return d*e+f

    def main_function(a=2, b=3, c=4, d=5, e=6, f=7):
        return subfunction_1(a=a, b=b, c=c) + subfunction_2(d=d, e=e, f=f)

Here you can see that I had to redefine the defaults in the main_function.  In larger codebases, I find bugs often arise because defaults are defined in multiple places, and somebody changes them in a lower-level function but fails to realize that they are still defined differently in a higher function.

The only way I currently see to achieve this is not very nice at all, and completely obfuscates the signature of the function:

    def main_function(**kwargs):
        return subfunction_1(**{k: v for k, v in kwargs.items() if k in ['a', 'b', 'c']}) 
               + subfunction_2(**{k: v for k, v in kwargs.items() if k in ['d', 'e', 'f']})

What I was thinking was a "deferred" builtin that would just allow a lower function to define the value (and raise an exception if anyone tried to use it before it was defined)

    def main_function(a=deferred, b=deferred, c=deferred, d=deferred, e=deferred, f=deferred):
        return subfunction_1(a=a, b=b, c=c) + subfunction_2(d=d, e=e, f=f)

I assume this has been discussed before somewhere, but couldn't find anything on it, so please feel free to point me towards any previous discussion on the topic.  


_______________________________________________
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/