Function object has attributes __defaults__ and __kwdefaults__. I see that if a function has some default arguments then they are put as a tuple to __defaults__ but __kwdefaults__ is None. When is used attribute __kwdefaults__?
def foo(arg1, arg2, arg3, *args, kwarg1="FOO", kwarg2="BAR", kwarg3="BAZ"):
pass
print(foo.__kwdefaults__)
Output (Python 3):
{'kwarg1': 'FOO', 'kwarg2': 'BAR', 'kwarg3': 'BAZ'}
Since the *args would swallow all non-keyword arguments, the arguments after it have to be passed with keywords. See PEP 3102.
It is used for keyword-only arguments:
>>> def a(a, *, b=2): pass
...
>>> a.__kwdefaults__
{'b': 2}
>>> def a(*args, a=1): pass
...
>>> a.__kwdefaults__
{'a': 1}
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.
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.
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)
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}
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}