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?

+2


source to share


6 answers


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}

.)

+3


source


In Python, variables are just labels attached to values. So there is no way of knowing from another area what labels you used when calling the function.



+2


source


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.

+2


source


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}

      

+1


source


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.

0


source


You need to pass keys and values ​​as separate arguments:

keys = ('T', 'N', 'L')
values = (1.0, 20, 10)
d = dict(zip(keys, values))

      

In your code, the string args = (T,N,L)

is evaluated as args = (1.0, 20, 10)

, the "names" of the variables T, N, L are replaced with their values.

0


source







All Articles