If you need to figure out which of the locals() are the parameter names, you’ll need to do introspection, for example:
import inspect
def func(a, b, c):
d = None
return {
k: v for k, v in locals().items()
if k in inspect.getargs(func.__code__).args
}
Or maybe set up a decorator, so that the wrapper handles the simple case. But then you’ll have to design the way that the decorator holds on to and communicates back the determined locals() result.
If your goal is to just collect the named parameters, you can easily do this with locals, even if you are using other variables, just make sure it’s the first thing you do in the function:
def foo(a, b, c):
args = dict(locals())
# ... rest of the function
return args
What are the situations where this is an impractical solution?
Oh, I guess that solution doesn’t quite work because locals is going to include closure locals and not just the arguments. But still, I am pretty sure this covers most of the already very few situations where this would be helpful.
Otherwise, here is a completely general function that only uses sys._getframe:
def get_args():
frame = sys._getframe(1)
total_argcount = frame.f_code.co_argcount + frame.f_code.co_kwonlyargcount
total_argcount += bool(frame.f_code.co_flags & 4) # Check if we have *args
total_argcount += bool(frame.f_code.co_flags & 8) # Check if we have **kwargs
return {
name: frame.f_locals[name]
for name in frame.f_code.co_varnames[:total_argcount]
}
This is less cross-version compatible than a solution using inspect but that is unavoidable because there is no stability guarantees about these interfaces. But AFAIK, this should work for all currently active python versions.
Had you considered writing a decorator? It would inspect the function
signature (just once when the function gets defined) and wrap it in
logic to produce the dict at runtime. It even preprovide that dict as an
additional argument. It’s take a little effort to make it, but once
you’ve got it…