I want a function exactly like PHP's compact function.
i.e., if I pass in a list of variable names:
compact('var1','var2')
it returns me back a dict:
{'var1':var1, 'var2':var2}
I want a function exactly like PHP's compact function.
i.e., if I pass in a list of variable names:
compact('var1','var2')
it returns me back a dict:
{'var1':var1, 'var2':var2}
The variable name used in the caller is not easily available to the called function. It's probably possible to do with an advanced use of inspect
, but it might be better to rethink why you want the variable names.
UPDATE: Now that I know what your real need is ("I want to pass my variables to my template"), the answer is simple: use locals()
: it returns a dictionary mapping all your local variable names to their values.
UPDATE 2: How about this?:
def only(d, *keys):
"""Return the subset of dict `d` whose keys are in `keys`."""
return dict((k,v) for k,v in d.iteritems() if k in keys)
...
a = 17
b = 23
template_data = only(locals(), "a", "b")
The function does not see the names (if any!-) of its actual arguments -- nor in fact any indication whatsoever that those actual arguments are the results of expressions that happen to be single variables rather than constants, function calls, or other expressions of any kind whatsoever.
So, what you require, as you have specified it, is simply not feasible.
if you have a list called args and you want to put it into a dictionary called kwargs as in your example:
for k,v in enumerate(args):
kwargs["var%d"%(k+1)] = v
the keys are literally the index of the items in args, though; this can't be useful?
(1) Python is not PHP. (2) "variable name lost when passed into a function" is true.
Do Not Use Variables for this.
Do something simpler. Use the dict
function.
>>> dict( var1=1, var2='a', var3=1+3j )
{'var1': 1, 'var3': (1+3j), 'var2': 'a'}
That seems to do what you want. The variable "names" are in there exactly once. You don't really need to create other local, temporary variables.
This is awkward and has limits, but for the rest it works
def p(*args):
p = {}
for i in args:
exec 'p["%s"] = %s' % (i, i)
return p
>>> import inspect
>>> def compact(*args):
... d = {}
... for a in args:
... d[a] = inspect.stack()[1][0].f_locals[a]
... return d
...
>>> def test():
... x = 5
... print compact('x')
...
>>> test()
{'x': 5}
With the help of Getting method parameter names in python, here you go with decorator
solution, so that you are able to apply it to any function:
def compactor(func):
import inspect
def compactor_impl(*args, **kwargs):
arg_names = inspect.getargspec(func)[0]
return dict(zip(arg_names, args))
return compactor_impl
@compactor
def package(var1, var2, var3):
pass
@compactor
def package2(var1, var2, var3, supervar):
pass
assert package(1, 2, 3) == {'var1': 1, 'var2': 2, 'var3': 3,}
assert package2(1, 2, 3, 'boh') == {'var1': 1, 'var2': 2, 'var3': 3, 'var3': 3, 'supervar': 'boh'}
I assumed that the functions do nothing else but return the name-value
pairs. You might want to add some checks (asserts) to ensure that len(args) == len(arg_names)
and that kwargs
is empty, because this will not be checked once the decorator is applied.