I have a Python (3) function
def f(a, b, c=1, d=2):
pass
I would like to build up a list of arguments in code. The actual use-case is to do this based on some command line argument parsing, but it's a general question (I'm fairly new to python) e.g.
myargs = {}
myargs['positionalParams'] = ['foo', 'bar']
myargs['c']=2
myargs['d']=3
f(myargs)
I know that I can do f(*somelist) to expand a list into separate args, but how to do that with a mix of positional and optional params? Or do I do it twice, once for positionals and once for a dict of others?
args = ['foo', 'bar']
kwargs = {'c': 2, 'd': 3}
f(*args, **kwargs)
Note that this will also do just fine:
kwargs = {'a': 'foo', 'b': 'bar', 'c': 2, 'd': 3}
f(**kwargs)
how to do that with a mix of positional and optional params?
You can pass values to positional arguments also with a dictionary by unpacking it like this
>>> def func(a, b, c=1, d=2):
... print(a, b, c, d)
...
...
>>> myargs = {"a": 4, "b": 3, "c": 2, "d": 1}
>>> func(**myargs)
4 3 2 1
Or do I do it twice, once for positionals and once for a dict of others?
Yes. You can unpack the values for the positional arguments also, like this
>>> pos_args = 5, 6
>>> keyword_args = {"c": 7, "d": 8}
>>> func(*pos_args, **keyword_args)
5 6 7 8
Or you might choose to pass the values explicitly, like this
>>> func(9, 10, **keyword_args)
9 10 7 8
Related
I have a problem with Code from the Mininet open source project. I abstracted it to the following scenario:
def bar (*a, **b):
b.update({'a':(a,)})
foo(**b)
def foo (*a, **c):
print(c)
print(a)
if __name__ == '__main__':
bar(2,3,4, x=3, y=5)
Method bar is only a helper to create a function call of foo.
If I run it, print(a) has no output, because the values are still stored in the dictionary b. If I change *a to a, it works fine.
And here my question:
Is there a possibility which does not modify the Method foo which puts data into *a with data and the call of foo is like in line 3? This means only b in method bar is allowed to be modified.
I don't think it's possible to comply both your conditions.
If the method foo stays the same the parameter *a represents a list of arguments with no name (like bar(2,3,4) in your example). And the call to foo(**b) in line 3 means passing keyword args (like bar(x=3, y=5) in your example) so they will be passed to **c as it is the keyword argument in foo.
Ok So I want to make you understand instead of just giving the answer because StackOverflow is all about explaining the concept instead of writing code, let's understand few points :
*args and **kwargs are use as arbitrary number of arguments.
Kwargs ** syntax requires a mapping (such as a dictionary); each
key-value pair in the mapping becomes a keyword argument.
while
*args recieves a tuple containing the positional arguments.
Now let's take simple example to understand your problem:
def check(*a,**b):
print(a)
print(b)
Now *a require a tuple or list or positional argument while **b require dict format keyworded argument.
One more point before jumping into the problem:
*l idiom is to unpack argument lists,tuples,set
a,*b=(1,2,3,4,5)
print(a)
print(b)
output:
1
[2, 3, 4, 5]
Now if i call that function something like:
def check(*a,**b):
print("value_a {}".format(a))
print("value_b {}".format(b))
print(check({'y': 5, 'x': 3, 'a': 5,'r':56}))
Now *a will take the value because there is no keyworded argument :
value_a ({'x': 3, 'y': 5, 'a': 5, 'r': 56},)
But let's add few keywords argument:
print(check({'y': 5, 'x': 3, 'a': 5,'r':56},key_s=5,values=10))
output:
value_a ({'a': 5, 'y': 5, 'r': 56, 'x': 3},)
value_b {'key_s': 5, 'values': 10}
Let's start using unpack method :
print(check(*{'y': 5, 'x': 3, 'a': 5,'r':56}))
output will be:
value_a ('r', 'x', 'y', 'a')
value_b {}
None
Because as i shown you * will unpack the keys of dict and it will treat them as the positional argument not keyworded argument.
Now let's use ** unpacking which will unpack dict as key,value pairs :
I think you got the point , Now let's use ** for mapping dict so it will unpack the dict and each key, value will be keyword argument :
print(check(**{'y': 5, 'x': 3, 'a': 5,'r':56}))
output:
value_a ()
value_b {'y': 5, 'r': 56, 'a': 5, 'x': 3}
So everything is clear now I think.
Now let's back to your problem :
As you said if you are using:
def check(a,**b):
print("value_a {}".format(a))
print("value_b {}".format(b))
print(check(**{'y': 5, 'x': 3, 'a': 5,'r':56}))
You are getting result because it's taking 'a' value from dict , and rest of values are taken by **b
Now if you want to use *a and **b then you have to provide :
the positional argument for *a
Keyworded argument for **b
As you said you don't want to modify foo then, You can try something like this:
def bar (*a, **b):
foo((a,),**b)
def foo (*a, **c):
print(c)
print(a)
if __name__ == '__main__':
bar(2,3,4, x=3, y=5)
output:
{'y': 5, 'x': 3}
(((2, 3, 4),),)
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 know I can turn function arguments into a dictionary if the function takes in **kwargs.
def bar(**kwargs):
return kwargs
print bar(a=1, b=2)
{'a': 1, 'b': 2}
However, is the opposite true? Can I pack named arguments into a dictionary and return them? The hand-coded version looks like this:
def foo(a, b):
return {'a': a, 'b': b}
But it seems like there must be a better way. Note that i am trying to avoid using **kwargs in the function (named arguments work better for an IDE with code completion).
It sounds like you are looking for locals:
>>> def foo(a, b):
... return locals()
...
>>> foo(1, 2)
{'b': 2, 'a': 1}
>>> def foo(a, b, c, d, e):
... return locals()
...
>>> foo(1, 2, 3, 4, 5)
{'c': 3, 'b': 2, 'a': 1, 'e': 5, 'd': 4}
>>>
Note however that this will return a dictionary of all names that are within the scope of foo:
>>> def foo(a, b):
... x = 3
... return locals()
...
>>> foo(1, 2)
{'b': 2, 'a': 1, 'x': 3}
>>>
This shouldn't be a problem if your functions are like that given in your question. If it is however, you can use inspect.getfullargspec and a dictionary comprehension to filter locals():
>>> def foo(a, b):
... import inspect # 'inspect' is a local name
... x = 3 # 'x' is another local name
... args = inspect.getfullargspec(foo).args
... return {k:v for k,v in locals().items() if k in args}
...
>>> foo(1, 2) # Only the argument names are returned
{'b': 2, 'a': 1}
>>>
I understand that how * and ** operators generally work. In the following code [ taken from django's source ]
def curry(_curried_func, *args, **kwargs):
def _curried(*moreargs, **morekwargs):
return _curried_func(*(args + moreargs), **dict(kwargs, **morekwargs))
return _curried
I get how the args + moreargs part work - the [non - keyword ] arguments passed initially to the function curry and the arguments passed to the curried function returned by curry are combined. What I don't get is how the **dict(kwargs, **morekwargs) works. Could someone please explain that bit?
dict(kwargs, **morekwargs) is a trick (that Guido dislikes) for combining 2 dictionaries into 1.
>>> d = {'foo':'bar'}
>>> kwargs = {'bar':'baz'}
>>> dict(d,**kwargs)
{'foo': 'bar', 'bar': 'baz'}
So, the curried function takes all kwargs passed to curry and adds them to the additional kwargs passed to the _curried function to create a super dictionary. that super dictionary gets unpacked and sent on to the _curried_func.
It effectively builds a union of two dicts, kwargs and morekwargs. Example:
>>> kwargs = {"ham": 1, "spam": 2}
>>> morekwargs = {"spam": 3, "eggs": 2}
>>> dict(kwargs, **morekwargs)
{'eggs': 2, 'ham': 1, 'spam': 3}
This works because the dict constructor takes keyword arguments, so it's the same as
>>> dict(kwargs, spam=3, eggs=2)
{'eggs': 2, 'ham': 1, 'spam': 3}
Finally, the resulting dict is fed as keyword arguments to _curried_func by means of **.
For example, I have a function:
def foo(a, b, c):
pass
Now I have a dict:
d = {'a': 1, 'b': 2, 'c': 3}
I have to write something like:
foo(d['a'], d['b'], d['c'])
I'd like to know, could I just pass a collection of the arguments(like d) to the function?
Sure, you can pass a dict as kwargs:
def foo(a, b, c):
print a, b, c
d = {'a': 1, 'b': 2, 'c': 3}
foo(**d)
Output:
1 2 3
Use the dictionary unpacking operator (**):
foo(**d)
foo(**d) should work.
See http://docs.python.org/tutorial/controlflow.html#unpacking-argument-lists