Reputation: 4703
If I have a Python function defined as f(a, b, c)
, is there a straightforward way to get a dictionary mapping the formal names to the values passed in? That is, from inside f
, I'd like to be able to get a dictionary {'a': 1, 'b': 2, 'c': 3}
for the call f(1, 2, 3)
.
I'd like to do this so I can directly use the arguments and values in a string substitution, e.g. "%(a)s %(b)s %(c)s" % d
. I could just do something like d = dict(a=a, b=b, c=c)
, but I'd rather avoid the repetition if possible.
I know this is quite easy to do by defining f
as f(**kwds)
, but that also makes it less obvious what arguments the function expects. It looks like there'd probably be some way to do this via the inspect
module, but it'd probably be too complex to be worthwhile.
I suspect there's no good answer to this question as posed, but I'd be happy to be proven wrong. Alternative approaches for accomplishing what I described above would be welcome too.
Upvotes: 5
Views: 257
Reputation: 362836
>>> import inspect
>>> def foo(a,b,c):
... pass
...
>>> inspect.getargspec(foo)
ArgSpec(args=['a', 'b', 'c'], varargs=None, keywords=None, defaults=None)
>>> inspect.getargspec(foo).args
['a', 'b', 'c']
Now you can filter locals()
based on those.
>>> x = 'outer'
>>> G = 'GLOBAL'
>>> def foo(a, b, c=1, *splat, **splatsplat):
... global G
... d = 'inner'
... b = 'stomped'
... print(locals())
... print(inspect.getargspec(foo))
...
>>> foo(1, 2, 3, 'splat1', 'splat2', named='potato')
{'splatsplat': {'named': 'potato'}, 'splat': ('splat1', 'splat2'), 'd': 'inner', 'b': 'stomped', 'c': 3, 'a': 1}
ArgSpec(args=['a', 'b', 'c'], varargs='splat', keywords='splatsplat', defaults=(1,))
The only thing I don't know how to get is to recover the original value of b
; I think that's probably impossible.
Upvotes: 7
Reputation: 31260
You could do it with two functions, one with a nice interface and the other with the implementation:
def f(a, b, c):
"""Docstring"""
return _f(a, b, c)
def _f(**kwargs):
...
Upvotes: 1
Reputation: 123473
You could avoid even more repetition by instead creating a generic function that does the string substitution as well. The following works in both Python 2.7.6 and 3.3.4:
import inspect
import sys
def print_func_args(call_stack_depth=1):
frame = sys._getframe(call_stack_depth)
funcname = inspect.getframeinfo(frame).function
func = frame.f_globals[funcname]
f_locals = frame.f_locals
args = inspect.getargspec(func).args
print(', '.join(('{}={}'.format(arg, f_locals[arg]) for arg in args)))
def foo(a, b, c):
local_var = 42
print_func_args()
foo(1, 2, 3) # -> a=1, b=2, c=3
Upvotes: 0
Reputation: 20371
You can use locals()
for the current scope:
>>> def f(a, b, c):
... param_values = locals() # Line must be very first in function.
... print(param_values)
>>> f(1, 2, 3)
{'a': 1, 'b': 2, 'c': 3}
Conveniently, this seems to be the exact output that you want. In my opinion, this is the best way to do it from inside the function as you specified.
Upvotes: 3