
On Sun, Nov 14, 2021 at 2:50 PM Chris Angelico <rosuav@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).