Python: a function that returns a dict whose keys are the names of the input arguments
Is it possible to write a function f
that accepts an arbitrary set of mixed data:
T = 1.0
N = 20
L = 10
args = (T,N,L)
f(*args) # or maybe f(T,N,L)?
and is returned as a result:
{'T':1.0, 'N':20, 'L':10}
There is a related question using local
, but I seem to be losing the names after passing them to the function. Is there a way to prevent this? I am assuming that the variables are passed by value and therefore are considered new objects.
Followup: Python: using a dummy class to pass variable names?
source to share
No, it's not possible at all in *args
. You will have to use keyword arguments:
>>> def f(**kwargs):
... return kwargs
...
>>> f(T=1.0, N=20, L=10)
{'T': 1.0, 'L': 10, 'N': 20}
This is because it *args
does not enter names for individual arguments; he only enters the name args
for the entire list. The function has no idea what names, if any, are outside the argument.
When the number of arguments is fixed, you can do it with locals
:
>>> def g(T, N, L):
... return locals()
...
>>> g(T=1.0, N=20, L=10)
{'L': 10, 'T': 1.0, 'N': 20}
(or explicitly with return {'T': T, 'N': N, 'L': L}
.)
source to share
Your guess is unfortunately wrong, and in fact the whole question is throwing away a misunderstanding of how Python names work.
Python objects generally don't know their names. This is understandable when you consider that you can easily assign a=b
and now a
, and b
both refer to the exact same object. Python "variables" are just names that refer to objects; they do not contain those objects in any real way. When you pass arguments to a function, you are passing in base objects, not names. The receive function just binds them to the names given in the function signature, or, in your case, just stores them in args
without giving them any names.
So when you ask how to get the names that objects in another area had, you cannot ask about the objects yourself. There is probably a way to do this, but it involves trickery when checking the calling frames, and I highly doubt you want it.
source to share
Solution using globals()
. This will only work if the values are unique in the scope of the module, so it's fragile - if there are duplicates, it will pick the first name that points to that value, somewhat arbitrary. And yes, you're probably better off not doing this anyway and rethinking the problem.
def f(*names):
r = {}
for n in names:
r[[ name for name in globals() if globals()[name] is n ][0]] = n
return r
T = 1.0
N = 20
L = 10
print f(T,N,L)
{'T': 1.0, 'L': 10, 'N': 20}
source to share
Yes, as far as I know, args is a list. To keep the shortcut names you need to pass the dict to ** kwargs and set the names explicitly or programmatically with local
.
You can do something like:
def filter_locals(caller_locals, *args):
filtered = {}
for key in args:
filtered[key] = caller_locals[key]
return filtered
Then:
X = 1 Y = 2 func(filter_locals(locals(), 'X', 'Y')
If func treats an arbitrary list of lengths as kwargs.
source to share