I want to use kwargs in Python like this:
def myfunc(**kwargs):
... do something ...
x = myfunc(a=1, b=2, #value=4)
But I can't, because #value is not a valid Python keyword
Alternatively, I can do this:
x = myfunc(**{'a':1, 'b':2, '#value': 4})
which is kind of awkward.
Is there any way I can use some kind of hybrid approach here?
# this doesn't work
x = myfunc(a=1,b=2, {'#value': 4})
Sure you can:
x = myfunc(a=1, b=2, **{'#value': 4})
Using explicit keyword parameters does not prevent you from passing in a dictionary as well.
Demo:
>>> def myfunc(**kwargs):
... print kwargs
...
>>> myfunc(a=1, b=2, **{'#value': 4})
{'a': 1, 'b': 2, '#value': 4}
Related
What is a proper way in Python to write a function that will return the very same parameters it received at run-time?
E.g.:
def pass_thru(*args, **kwargs):
# do something non-destructive with *args & **kwargs
return ??? <- somehow return *args & **kwargs
Consider the following function:
def a(*args, **kwargs):
return args, kwargs
When we call the function, the value returned is a tuple, containing first another tuple with the arguments, then a dictionary with the keyword arguments:
b = a(1, 2, 3, a='foo')
print(b)
Outputs: ((1, 2, 3), {'a': 'foo'})
print(b[0]) # Gives the args as a tuple
print(b[1]) # Gives the kwargs as a dictionary
The problem is that your arguments are just a sequence of values, not a value itself you can manipulate. Keyword arguments are not themselves first-class values (that is, a=3 is not a value); they are purely a syntactic construct.
* and ** parameters get you halfway there:
def pass_thru(*args, **kwargs):
return *args, kwargs
Then
>>> pass_thru(1, 2, a=3)
(1, 2, {'a': 3})
but you can't simply pass that back to pass_thru; you'll get a different result.
>>> pass_thru(pass_thru(1,2,a=3))
((1, 2, {'a': 3}), {})
You can try unpacking the tuple:
>>> pass_thru(*pass_thru(1,2,a=3))
(1, 2, {'a': 3}, {})
but what you really need is to unpack the dict as well. Something like
>>> *a, kw = pass_thru(1,2,a=3)
>>> pass_thru(*a, **kw)
(1, 2, {'a': 3})
As far as I know, there is no way to combine the last example into a single, nested function call.
Assume now I have a well-defined function
def f1(a):
...
and i can not change its definition. Now I want to call it with a argument from a dictionary
D={ 'a':1 , 'b':2}
If I call it like
f1(**D)
there will be a syntax error (because b is not defined in f1). My question is if I can find a smart way to let the function to find the argument it needed only?
You can use inspect.getargspec:
d = {'a': 5, 'b': 6, 'c': 7}
def f(a,b):
return a + b
f(*[d[arg] for arg in inspect.getargspec(f).args])
which gives 11.
Thanks Eugene, getargspec is legacy, instead you should use getfullargspec which has the same usage in this case.
You could get the argument names from the function's code object, then lookup the values for them in the dictionary:
>>> def f(a):
... b = 2
... return a + b
...
>>> D = {'a': 1, 'b': 2, 'c': 3}
>>> nargs = f.__code__.co_argcount
>>> varnames = f.__code__.co_varnames
>>> f(*(D[arg] for arg in varnames[:nargs]))
3
Here is an example of function that got a dictionary and use only the 'b' key :
In [14]: def f1(mydict):
...: return mydict['b']
...:
In [15]: x={'a': 1, 'b':2}
In [16]: f1(x)
Out[16]: 2
I'd like to call a function in python using a dictionary with matching key-value pairs for the parameters.
Here is some code:
d = dict(param='test')
def f(param):
print(param)
f(d)
This prints {'param': 'test'} but I'd like it to just print test.
I'd like it to work similarly for more parameters:
d = dict(p1=1, p2=2)
def f2(p1, p2):
print(p1, p2)
f2(d)
Is this possible?
Figured it out for myself in the end. It is simple, I was just missing the ** operator to unpack the dictionary
So my example becomes:
d = dict(p1=1, p2=2)
def f2(p1,p2):
print p1, p2
f2(**d)
In[1]: def myfunc(a=1, b=2):
In[2]: print(a, b)
In[3]: mydict = {'a': 100, 'b': 200}
In[4]: myfunc(**mydict)
100 200
A few extra details that might be helpful to know (questions I had after reading this and went and tested):
The function can have parameters that are not included in the dictionary
You can not override a function parameter that is already in the dictionary
The dictionary can not have values that aren't in the function.
Examples:
Number 1: The function can have parameters that are not included in the dictionary
In[5]: mydict = {'a': 100}
In[6]: myfunc(**mydict)
100 2
Number 2: You can not override a function parameter that is already in the dictionary
In[7]: mydict = {'a': 100, 'b': 200}
In[8]: myfunc(a=3, **mydict)
TypeError: myfunc() got multiple values for keyword argument 'a'
Number 3: The dictionary can not have values that aren't in the function.
In[9]: mydict = {'a': 100, 'b': 200, 'c': 300}
In[10]: myfunc(**mydict)
TypeError: myfunc() got an unexpected keyword argument 'c'
How to use a dictionary with more keys than function arguments:
A solution to #3, above, is to accept (and ignore) additional kwargs in your function (note, by convention _ is a variable name used for something being discarded, though technically it's just a valid variable name to Python):
In[11]: def myfunc2(a=None, **_):
In[12]: print(a)
In[13]: mydict = {'a': 100, 'b': 200, 'c': 300}
In[14]: myfunc2(**mydict)
100
Another option is to filter the dictionary based on the keyword arguments available in the function:
In[15]: import inspect
In[16]: mydict = {'a': 100, 'b': 200, 'c': 300}
In[17]: filtered_mydict = {k: v for k, v in mydict.items() if k in [p.name for p in inspect.signature(myfunc).parameters.values()]}
In[18]: myfunc(**filtered_mydict)
100 200
Example with both positional and keyword arguments:
Notice further than you can use positional arguments and lists or tuples in effectively the same way as kwargs, here's a more advanced example incorporating both positional and keyword args:
In[19]: def myfunc3(a, *posargs, b=2, **kwargs):
In[20]: print(a, b)
In[21]: print(posargs)
In[22]: print(kwargs)
In[23]: mylist = [10, 20, 30]
In[24]: mydict = {'b': 200, 'c': 300}
In[25]: myfunc3(*mylist, **mydict)
10 200
(20, 30)
{'c': 300}
In python, this is called "unpacking", and you can find a bit about it in the tutorial. The documentation of it sucks, I agree, especially because of how fantasically useful it is.
Here ya go - works just any other iterable:
d = {'param' : 'test'}
def f(dictionary):
for key in dictionary:
print key
f(d)
I have this code:
class Test(object):
def f1(self,*args,**kwargs):
print args
print kwargs
self.f2(*args,**kwargs)
def f2(self,*args,**kwargs):
print "calling f2"
print "args= ",args
print "kwargs= ",kwargs
t = Test()
args = [1,2,3]
kwargs= {'a':1,'b':2}
t.f1(args,kwargs)
#second call
t.f1(kwargs)
and it prints
([1, 2, 3], {'a': 1, 'b': 2})
{}
calling f2
args= ([1, 2, 3], {'a': 1, 'b': 2})
kwargs= {}
({'a': 1, 'b': 2},)
{}
calling f2
args= ({'a': 1, 'b': 2},)
kwargs= {}
I want to make *args in the construct optional. That is if I pass dict, it is taken as args in the second call above. I do not want that.
I basically want this construct:
f1(*args,**kwargs)
-- if *args is present, then process *args
if it is not present, then process **kwargs, but do not take the dict passed to be *args
That is because I will not be passing dict to *args in any case.
t = Test()
args = [1,2,3]
kwargs= {'a':1,'b':2}
t.f1(args,kwargs)
t.f1(kwargs)
Needs to be
t = Test()
args = [1,2,3]
kwargs= {'a':1,'b':2}
t.f1(*args,**kwargs)
t.f1(**kwargs)
Otherwise it passes args and kwargs as the first and second argument (which both get collapsed to *args inside the function)
You had argument unpacking correct, but hadn't added the proper syntax for argument packing.
You're doing it wrong.
t.f1(*args, **kwargs)
t.f1(**kwargs)
What is context in python, in particular what does **context mean? Is it a way to pass the variables in the current context around? A code example will be most appreciated.
from mako.template import Template
template = Template('var1 = ${var1}')
for v in range(1, 5):
context = {'var1': v}
print template.render(**context)
The ** operator, when it appears in a function call, converts a dictionary into a set of keyword arguments to a function. When it appears in a function definition, it converts a set of keyword arguments to a function into a dictionary. So for example:
>>> d = {'a':0, 'b':1, 'c':2}
>>> def print_my_arguments(**my_arguments):
... print my_arguments
...
>>> print_my_arguments(a=0, b=1, c=2)
{'a': 0, 'c': 2, 'b': 1}
>>> print_my_arguments(**d)
{'a': 0, 'c': 2, 'b': 1}
In your case anything you pass to render as a kwarg is passed as a Context to your template in order to render.
The context represents a dictionary of data available to the page/template while rendering. So when you do something like
context = {'var1': v}
and your template has code like
$(var1)
It would print v
Mako resolves this by looking to the Context, which is just wraps a _data with the kwargs passed down to it via render.