Re: Auto-assign attributes from __init__ arguments

Steven D'Aprano wrote:
I took a stab at this. This should work regardless of where the function is defined. ``` import inspect def parameters(*, expand_kwargs=True): frame = inspect.currentframe().f_back code = frame.f_code varnames = code.co_varnames end = code.co_argcount + code.co_kwonlyargcount result = { name: frame.f_locals[name] for name in varnames[:end] } # **kwargs if code.co_flags & inspect.CO_VARKEYWORDS: index = end if code.co_flags & inspect.CO_VARARGS: index += 1 name = varnames[index] var = frame.f_locals[name] if expand_kwargs: result.update(var) else: result[var] = name return result def foo1(a, b=1, *args, c, **d): x = 1 y = 2 print(parameters()) print(a, b, c, d) foo2(**parameters()) def foo2(a, b=1, *args, c, **d): print(a, b, c, d) foo1(1, 2, 3, 4, c=5, e=6, f=7) ``` Output: ``` {'a': 1, 'b': 2, 'c': 5, 'e': 6, 'f': 7} 1 2 5 {'e': 6, 'f': 7} 1 2 5 {'e': 6, 'f': 7} ``` Note that `parameters()` intentionally doesn't contain `'args': (3, 4)` because then `foo2(**parameters())` would see `args` as a keyword argument within `d` instead of bound to the parameter `*args`. So naturally I tried `foo2(*args, **parameters())` but that gave me `TypeError: foo2() got multiple values for argument 'a'`. So if you want to pass all arguments from one function to another, you need more than a dict if the inner signature include `*args`, and obviously even more so if it includes positional only parameters.
participants (1)
-
Alex Hall