how to make *args optional in python when **kwargs is given? - python

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)

Related

Make a Python function that returns the same arguments as it receives

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.

Python: Forward a dictionary to another function [duplicate]

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)

Pass keyword arguments as required arguments in Python

I have, for example, 3 functions, with required arguments (some arguments are shared by the functions, in different order):
def function_one(a,b,c,d,e,f):
value = a*b/c ...
return value
def function_two(b,c,e):
value = b/e ..
return value
def function_three(f,a,c,d):
value = a*f ...
return value
If I have the next dictionary:
argument_dict = {'a':3,'b':3,'c':23,'d':6,'e':1,'f':8}
Is posible to call the functions in this way??:
value_one = function_one(**argument_dict)
value_two = function_two (**argument_dict)
value_three = function_three (**argument_dict)
Not the way you have written those functions, no: they are not expecting the extra arguments so will raise a TypeError.
If you define all the functions as also expecting **kwargs, things will work as you want.
I assume what you're trying to do is to create a function with an undefined number of arguments. You can do this by using args (arguments) or kwargs (key word arguments kind of foo='bar') style so for example:
for arguments
def f(*args): print(args)
f(1, 2, 3)
(1, 2, 3)`
then for kwargs
def f2(**kwargs): print(kwargs)
f2(a=1, b=3)
{'a': 1, 'b': 3}
Let's try a couple more things.
def f(my_dict): print (my_dict['a'])
f(dict(a=1, b=3, c=4))
1
It works!!! so, you could do it that way and complement it with kwargs if you don't know what else the function could receive.
Of course you could do:
argument_dict = {'a':1, 'b':3, 'c':4}
f(argument_dict)
1
So you don't have to use kwargs and args all the time. It all depends the level of abstraction of the object you're passing to the function. In your case, you're passing a dictionary so you can handle that guy without only.

calling Python kwargs functions with special keys

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}

How come this python class prints out my kwargs?

class Meta(dict):
def __init__(self, indexed, method, *args, **kwargs):
super(Meta, self).__init__(*args, **kwargs)
print self
How come this prints my kwargs?
m = Meta(indexed='hello', method='distance', a='3', b='4')
When I run this, it prints out a dictionary with my kwargs, when I'm expecting an empty dictionary...
Why do you expect self not to contain your keyword args, when you explicitly initialized your instance (a dict subclass) with the keyword args by calling the dict class's initializer?
That's because the dict class initializes its contents from the keyword arguments passed to its constructor:
>>> dict(indexed='hello', method='distance', a='3', b='4')
{'a': '3', 'indexed': 'hello', 'b': '4', 'method': 'distance'}
Since your class calls dict's constructor with the keyword arguments passed to its own constructor, the dictionary is indeed initialized and the same behavior is observed.
Why shouldn't it? The class inherits the related str and repr implementation from dict.
The statement print self in the constructor is effectively printing your kwargs. This is because of the behavior you inherited from the dict class. The kwargs are included in the dictionary store.
>>> d = dict(a=3, b=4)
>>> print d
{'a': 3, 'b': 4}
Because your are passing them to the initializer of dict.
try that:
>>> dict(a=1, b=2, c=3)
{'a': 1, 'c': 3, 'b': 2}

Categories