On Sun, Nov 14, 2021 at 2:50 PM Chris Angelico <ros...@gmail.com> wrote:

>
> spam(*(1,) * use_eggs)
> spam(**{"eggs": 1} if use_eggs else {})
>
> Still clunky, but legal, and guaranteed to work in all Python
> versions. It's not something I've needed often enough to want
> dedicated syntax for, though.
>
> ChrisA
>

The thing is that I find myself dealing with duplicated defaults *all the
time *- and I don't know a good way to solve the problem.  The "**{"eggs":
1} if use_eggs else {}" is obviously problematic because
* It is immune to type-inspection, pylint, mypy, IDE-assisted-refactoring,
etc,
* If trying to *pass down* the argument it actually looks like
spam(**{"eggs": kwargs["eggs"]} if "eggs" in kwargs else {}) which is even
messier

A lot of the time, my code looks like this:

    def main_demo_func_with_primative_args(path: str, model_name: str,
param1: float=3.5, n_iter: float=7):
        obj = BuildMyObject(
            model_name = model_name,
            sub_object = MySubObject(param1=param1, n_iter=n_iter)
        )
        for frame in iter_frames(path):
            result = obj.do_something(frame)
            print(result)

ie I have a main function with a list of arguments that are distributed to
build objects and call functions.

The problem is I am always dealing with duplicated defaults (between this
main function and the default values on the objects).  You define a
default, duplicate it somewhere else, change the original, forget to change
the duplicated, etc...

* It makes sense to define the default values in one place.
* It makes sense for this place to be on the objects which use them (ie at
the lowest level)
* It makes sense to be able to modify default values from the top level
function.
But the above 3 things are not compatible in current python (at least not
in a clean, pythonic way!)

The only ways I know of to avoid duplication are:
* Define the defaults as GLOBALS in the module of the called function/class
and reference them from both places (not always possible as you don't
necessarily control the called code).  Also not very nice because you have
to define a new global for each parameter of each low-level object (a a
different sort of duplication).
* Messy dict-manipulation with kwargs (see above)
* Messy and fragile default inspection using inspect module

The only decent ways I can think of to avoid duplicated-defaults are not
currently supported in Python:

1) Conditional arg passing (this proposal):
        def main_func(..., param_1: Optional[float] = None, n_iter:
Optional[int] = None):
            sub_object = MySubObject(param1=param1 if param1 is not None,
n_iter=n_iter if n_iter is not None)

2) Ability to cleanly reference defaults of a lower-level object:
         def main_func(..., param_1: float=MySubObject.defaults.param1,
n_iter: int=MySubObject.defaults.n_iter):
             sub_object = MySubObject(param1=param1, n_iter=n_iter)

3) "Deferred defaults
<https://marc.info/?l=python-ideas&m=131066811311230&w=2>"... which seem to
be a bit of a Pandora's box

(1) seems less controversial than (2).
_______________________________________________
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/JJSXU5E2KKRVSQJH3TOZTYYMCNCEUCEA/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to