Steven D'Aprano wrote:
> Proposal:
> We should have a mechanism that collects the current function or
> method's parameters into a dict, similar to the way locals() returns all
> local variables.
> This mechanism could be a new function,or it could even be a magic local
> variable inside each function, similar to what is done to make super()
> work. But for the sake of this discussion, I'll assume it is a function,
> parameters(), without worrying about whether it is a built-in or
> imported from the inspect module.
> So given a function signature:
> def func(spam, eggs, cheese=None):
>
> and a call to it func(1, 2), then inside the body of the function,
> calling parameters() will return the dict:
> {'spam': 1, 'eggs': 2, 'cheese': None}
> [...]
> Another pattern would be to pass on your parameters to the superclasses:
> super().method(**parameters())

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.
_______________________________________________
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/QQKU24OU67ZPPFSWJHN7OCJXR7V2Z62A/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to