# How to get the set of all arguments in Python?

7
Python has both positional and named parameters as `*` and `**` operators that allow you to receive an arbitrary number of additional arguments:

``````def foo(a, b, c=1, *args, **kwargs):
print(a, b, c, args, kwargs)

foo(1, 2)          # 1, 2, 1, (), {}
foo(1, 2, 3)       # 1, 2, 3, (), {}
foo(1, 2, 3, 4)    # 1, 2, 3, (4,), {}
foo(1, 2, 3, 4, 5) # 1, 2, 3, (4,5), {}

foo(b=1, a=2)                # 2, 1, 1, (), {}
foo(b=1, a=2, c=3)           # 2, 1, 3, (), {}
foo(b=1, a=2, c=3, d=4)      # 2, 1, 3, (), {'d':4}
foo(b=1, a=2, c=3, d=4, e=5) # 2, 1, 3, (), {'d':4, 'e':5}

foo(1, 2, 3, 4, 5, d=6, e=7) # 1 2 3 (4, 5) {'d': 6, 'e': 7}
``````

I wonder if in a case like this, you mix explicitly declared parameters with arbitrary argument lists / sets, if you can get the set of all of them , not just the additional ones. Example:

``````def foo(a, b, c=1, *args, **kwargs):
print(list_args(...))
print(dict_args(...))

foo(1, 2, 3, 4, 5, d=6, e=7)
# (1, 2, 3, 4, 5, 6, 7)
# {'a':1, 'b':2, 'c':3, 3:4, 4:5, 'd':6, 'e':7}
``````

(just one example, such a feature could have additional constraints - such as not mixing `*args` with `**kwargs` , or representing the arguments in a different way - but interestingly something like that existed / could be done)

Is it possible? Compare with the JavaScript language, which allows both named parameters and access to the list of all arguments via `arguments` :

``````function foo(a, b, c) {
console.log(arguments);
}

foo(1, 2, 3, 4, 5); // [1, 2, 3, 4, 5]
// Repare que o conjunto inclui "a", "b" e "c", ao contrário do Python
``````
Note: The motivation for this question is to find a way to create a function that has a well-defined set of parameters (with exact number and names, and maybe optional values) but can pass all of them (after some validation, or even change ) to another function that has exactly the same parameters.

asked by anonymous 24.11.2015 / 08:29

2

You can do:

``````import inspect

def func(a, b, c):
frame = inspect.currentframe() #equivalente a sys._getframe(0)
args_names, _, _, locals_ = inspect.getargvalues(frame)
args = [locals_[i] for i in args_names]
kwargs = dict(zip(args_names, args))
print "args: %r" %args
print "kwargs: %r" %kwargs

>>> func(1, 2, 3)
args: [1, 2, 3]
kwargs: {'a': 1, 'c': 3, 'b': 2}

>>> func(c=1, a=2, b=3)
args: [2, 3, 1]
kwargs: {'a': 2, 'c': 1, 'b': 3}
``````

You can do a function that dump the arguments:

``````import sys
import inspect

def dumpargs():
frame = sys._getframe(1) # 0: funcao atual, 1: pega a funcao anterior na pilha
args_names, _, _, locals_ = inspect.getargvalues(frame)
args = [locals_[i] for i in args_names]
kwargs = dict(zip(args_names, args))
return args, kwargs

def outra(a, b, c, d=1):
args, kwargs = dumpargs()
print "kwargs: %r" %kwargs
print "args: %r" %args

>>> outra(1, 2, 3)
kwargs: {'a': 1, 'c': 3, 'b': 2, 'd': 1}
args: [1, 2, 3, 1]

>>> outra(1, 2, 3, 4)
kwargs: {'a': 1, 'c': 3, 'b': 2, 'd': 4}
args: [1, 2, 3, 4]

>>> outra(b=1, c=2, d=3, a=4)
kwargs: {'a': 4, 'c': 2, 'b': 1, 'd': 3}
args: [4, 1, 2, 3]
``````

# Update 01

As noted by the question author, part of this code is only guaranteed to work in CPython. `sys._getframe` , for example, is specific to CPython there is no guarantee to work in PyPy , Jython, or another python implementation. Also, `inspect.getargvalues` is deprecated since python 3.5

# Update 02

The code works in `PyPy 2.6.0 (python 2.7.9)` and `Jython 2.7.0`

24.11.2015 / 18:34
1

I'm not sure what you really want, however, I believe I have a simpler approach.

Did you try calling `locals` right at the beginning of the function?

``````def foo(a, b, c=1, *args, **kw):
assinatura = locals()
print(assinatura)

In : foo(1, 2, 3, 4, 5, d=6, e=7)
{'kw': {'d': 6, 'e': 7}, 'args': (4, 5), 'a': 1, 'b': 2, 'c': 3}
``````

If you need something more accurate, I suggest that you use the `getfullargspec` method of the `inspect` module. It will return all the information about the function parameters, which can be compared with the result of `locals` .

25.11.2015 / 08:55