0

I have many different methods all in different classes with different function signatures that all have the same set of default parameters but usually have different non-default parameters. I wanted to make my code more loosely coupled by having these default parameters reference a variable instead of being hardcoded in each signature so in the case I wanted to change one of the defaults I wouldn't have to visit each method. For example, say I have a dictionary containing {'param1': True, 'param2': False, 'param3': 100} I would want to make each pair act as a default parameter. In theory, it would look something like this:

#So this
defaultParams = {'param1': True, 'param2': False, 'param3': 100}
def func(*args, **defaultParams) #thinking that you could 'spread' the default params into the function based off the var. Obv wouldn't work but that's the functionality I would want

#would be equivalent to this
def func(*args, param1=True, param2=False, param3=100)

#but would NOT look like this as I don't want to have to lookup an item to reference it:
def func(*args, kwargs=defaultParams)

Im wondering if this is possible in python and if it isn't if there is a design pattern that would accommodate this problem.

Thanks

lmjohns3
  • 7,422
  • 5
  • 36
  • 56
syntactic
  • 109
  • 6
  • 1
    I'd suggest encapsulating the parameters in some kind of options/config object rather than using kwargs. Then you can specify the defaults in that class's constructor. – Samwise May 19 '22 at 00:11
  • Does this answer your question? [Is it possible to change a function's default parameters in Python?](https://stackoverflow.com/questions/17625695/is-it-possible-to-change-a-functions-default-parameters-in-python) – BrokenBenchmark May 19 '22 at 00:14
  • 1
    Make your configuration object a [dataclass](https://docs.python.org/3/library/dataclasses.html). Preferably a frozen one. It's like a dictionary but you can give it a docstring and it makes type-checking easier if you go down that route. – Silvio Mayolo May 19 '22 at 00:16
  • 1
    To be clear: the idea is that multiple methods have a common set of parameters with the same names, and each method should have the same default value for the same given parameter, as each other method; and you want to be able to update all the default values in a common place? That sounds like exactly the job for some kind of data structure; why don't you want those lookups? You gain encapsulated data that you can then pass around as a unit. – Karl Knechtel May 19 '22 at 00:18

2 Answers2

1

You can't do this in the parameter list, but you can merge with the defaults inside the function.

defaultParams = {'param1': True, 'param2': False, 'param3': 100}

def func(**kwargs):
    kwargs = defaultParams | kwargs
Barmar
  • 741,623
  • 53
  • 500
  • 612
1

You could do this inside each function in question by doing dictionary updates:

def func(*args, **kwargs):
  kw = dict(defaultParams) | kwargs
  # ... proceed with computation

If you wanted to do this on many functions, you could potentially use a decorator:

def with_defaults(f):
  def wrapper(*args, **kwargs):
    kw = dict(defaultParams) | kwargs
    return f(*args, **kw)
  return wrapper

@with_defaults
def func(*args):
  # ...

I also feel like it's worth pointing out that this sort of pattern can be quite risky, given that dictionaries in Python are mutable -- if something changed defaultParams somewhere, then suddenly the behaviors of all your functions would change. You might mitigate this by making defaultParams a tuple of key-value ordered pairs. (Or, as others have suggested, using a dataclass, but I'm not sure if you'd then lose the dictionary update semantics.)

In addition, the signature information of the functions in question would be off. Probably there's a way to address this using some metaprogramming magic, but it would start to get complex quickly.

lmjohns3
  • 7,422
  • 5
  • 36
  • 56