New to Python, why is it not quoted? [duplicate] - python

This question already has answers here:
What does ** (double star/asterisk) and * (star/asterisk) do for parameters?
(25 answers)
Closed 1 year ago.
What are the uses for **kwargs in Python?
I know you can do an objects.filter on a table and pass in a **kwargs argument.  
Can I also do this for specifying time deltas i.e. timedelta(hours = time1)?
How exactly does it work? Is it classified as 'unpacking'? Like a,b=1,2?

You can use **kwargs to let your functions take an arbitrary number of keyword arguments ("kwargs" means "keyword arguments"):
>>> def print_keyword_args(**kwargs):
... # kwargs is a dict of the keyword args passed to the function
... for key, value in kwargs.iteritems():
... print "%s = %s" % (key, value)
...
>>> print_keyword_args(first_name="John", last_name="Doe")
first_name = John
last_name = Doe
You can also use the **kwargs syntax when calling functions by constructing a dictionary of keyword arguments and passing it to your function:
>>> kwargs = {'first_name': 'Bobby', 'last_name': 'Smith'}
>>> print_keyword_args(**kwargs)
first_name = Bobby
last_name = Smith
The Python Tutorial contains a good explanation of how it works, along with some nice examples.
Python 3 update
For Python 3, instead of iteritems(), use items()

Unpacking dictionaries
** unpacks dictionaries.
This
func(a=1, b=2, c=3)
is the same as
args = {'a': 1, 'b': 2, 'c':3}
func(**args)
It's useful if you have to construct parameters:
args = {'name': person.name}
if hasattr(person, "address"):
args["address"] = person.address
func(**args) # either expanded to func(name=person.name) or
# func(name=person.name, address=person.address)
Packing parameters of a function
Use .items() instead of .iteritems() for python 3
def setstyle(**styles):
for key, value in styles.iteritems(): # styles is a regular dictionary
setattr(someobject, key, value)
This lets you use the function like this:
setstyle(color="red", bold=False)
Notes
kwargs is variable name used for keyword arguments, another variable name can be used. The important part is that it's a dictionary and it's unpacked with the double asterisk operator **.
Other iterables are unpacked with the single asterisk operator *
To prevent confusion, it's probably best to stick with the recognized variable names, kwargs and args, for dictionaries and other iterables respectively.
Resources
PEP 448: Additional Unpacking Generalizations
Real Python: Python args and kwargs: Demystified
What do * and ** before a variable name mean in a function signature?

kwargs is just a dictionary that is added to the parameters.
A dictionary can contain key, value pairs. And that are the kwargs. Ok, this is how.
The what for is not so simple.
For example (very hypothetical) you have an interface that just calls other routines to do the job:
def myDo(what, where, why):
if what == 'swim':
doSwim(where, why)
elif what == 'walk':
doWalk(where, why)
...
Now you get a new method "drive":
elif what == 'drive':
doDrive(where, why, vehicle)
But wait a minute, there is a new parameter "vehicle" -- you did not know it before. Now you must add it to the signature of the myDo-function.
Here you can throw kwargs into play -- you just add kwargs to the signature:
def myDo(what, where, why, **kwargs):
if what == 'drive':
doDrive(where, why, **kwargs)
elif what == 'swim':
doSwim(where, why, **kwargs)
This way you don't need to change the signature of your interface function every time some of your called routines might change.
This is just one nice example you could find kwargs helpful.

On the basis that a good sample is sometimes better than a long discourse I will write two functions using all python variable argument passing facilities (both positional and named arguments). You should easily be able to see what it does by yourself:
def f(a = 0, *args, **kwargs):
print("Received by f(a, *args, **kwargs)")
print("=> f(a=%s, args=%s, kwargs=%s" % (a, args, kwargs))
print("Calling g(10, 11, 12, *args, d = 13, e = 14, **kwargs)")
g(10, 11, 12, *args, d = 13, e = 14, **kwargs)
def g(f, g = 0, *args, **kwargs):
print("Received by g(f, g = 0, *args, **kwargs)")
print("=> g(f=%s, g=%s, args=%s, kwargs=%s)" % (f, g, args, kwargs))
print("Calling f(1, 2, 3, 4, b = 5, c = 6)")
f(1, 2, 3, 4, b = 5, c = 6)
And here is the output:
Calling f(1, 2, 3, 4, b = 5, c = 6)
Received by f(a, *args, **kwargs)
=> f(a=1, args=(2, 3, 4), kwargs={'c': 6, 'b': 5}
Calling g(10, 11, 12, *args, d = 13, e = 14, **kwargs)
Received by g(f, g = 0, *args, **kwargs)
=> g(f=10, g=11, args=(12, 2, 3, 4), kwargs={'c': 6, 'b': 5, 'e': 14, 'd': 13})

Motif: *args and **kwargs serves as a placeholder for the arguments that need to be passed to a function call
using *args and **kwargs to call a function
def args_kwargs_test(arg1, arg2, arg3):
print "arg1:", arg1
print "arg2:", arg2
print "arg3:", arg3
Now we'll use *args to call the above defined function
#args can either be a "list" or "tuple"
>>> args = ("two", 3, 5)
>>> args_kwargs_test(*args)
result:
arg1: two
arg2: 3
arg3: 5
Now, using **kwargs to call the same function
#keyword argument "kwargs" has to be a dictionary
>>> kwargs = {"arg3":3, "arg2":'two', "arg1":5}
>>> args_kwargs_test(**kwargs)
result:
arg1: 5
arg2: two
arg3: 3
Bottomline : *args has no intelligence, it simply interpolates the passed args to the parameters(in left-to-right order) while **kwargs behaves intelligently by placing the appropriate value # the required place

kwargs in **kwargs is just variable name. You can very well have **anyVariableName
kwargs stands for "keyword arguments". But I feel they should better be called as "named arguments", as these are simply arguments passed along with names (I dont find any significance to the word "keyword" in the term "keyword arguments". I guess "keyword" usually means words reserved by programming language and hence not to be used by the programmer for variable names. No such thing is happening here in case of kwargs.). So we give names
param1 and param2 to two parameter values passed to the function as follows: func(param1="val1",param2="val2"), instead of passing only values: func(val1,val2). Thus, I feel they should be appropriately called "arbitrary number of named arguments" as we can specify any number of these parameters (that is, arguments) if func has signature func(**kwargs)
So being said that let me explain "named arguments" first and then "arbitrary number of named arguments" kwargs.
Named arguments
named args should follow positional args
order of named args is not important
Example
def function1(param1,param2="arg2",param3="arg3"):
print("\n"+str(param1)+" "+str(param2)+" "+str(param3)+"\n")
function1(1) #1 arg2 arg3 #1 positional arg
function1(param1=1) #1 arg2 arg3 #1 named arg
function1(1,param2=2) #1 2 arg3 #1 positional arg, 1 named arg
function1(param1=1,param2=2) #1 2 arg3 #2 named args
function1(param2=2, param1=1) #1 2 arg3 #2 named args out of order
function1(1, param3=3, param2=2) #1 2 3 #
#function1() #invalid: required argument missing
#function1(param2=2,1) #invalid: SyntaxError: non-keyword arg after keyword arg
#function1(1,param1=11) #invalid: TypeError: function1() got multiple values for argument 'param1'
#function1(param4=4) #invalid: TypeError: function1() got an unexpected keyword argument 'param4'
Arbitrary number of named arguments kwargs
Sequence of function parameters:
positional parameters
formal parameter capturing arbitrary number of arguments (prefixed with *)
named formal parameters
formal parameter capturing arbitrary number of named parameters (prefixed with **)
Example
def function2(param1, *tupleParams, param2, param3, **dictionaryParams):
print("param1: "+ param1)
print("param2: "+ param2)
print("param3: "+ param3)
print("custom tuple params","-"*10)
for p in tupleParams:
print(str(p) + ",")
print("custom named params","-"*10)
for k,v in dictionaryParams.items():
print(str(k)+":"+str(v))
function2("arg1",
"custom param1",
"custom param2",
"custom param3",
param3="arg3",
param2="arg2",
customNamedParam1 = "val1",
customNamedParam2 = "val2"
)
# Output
#
#param1: arg1
#param2: arg2
#param3: arg3
#custom tuple params ----------
#custom param1,
#custom param2,
#custom param3,
#custom named params ----------
#customNamedParam2:val2
#customNamedParam1:val1
Passing tuple and dict variables for custom args
To finish it up, let me also note that we can pass
"formal parameter capturing arbitrary number of arguments" as tuple variable and
"formal parameter capturing arbitrary number of named parameters" as dict variable
Thus the same above call can be made as follows:
tupleCustomArgs = ("custom param1", "custom param2", "custom param3")
dictCustomNamedArgs = {"customNamedParam1":"val1", "customNamedParam2":"val2"}
function2("arg1",
*tupleCustomArgs, #note *
param3="arg3",
param2="arg2",
**dictCustomNamedArgs #note **
)
Finally note * and ** in function calls above. If we omit them, we may get ill results.
Omitting * in tuple args:
function2("arg1",
tupleCustomArgs, #omitting *
param3="arg3",
param2="arg2",
**dictCustomNamedArgs
)
prints
param1: arg1
param2: arg2
param3: arg3
custom tuple params ----------
('custom param1', 'custom param2', 'custom param3'),
custom named params ----------
customNamedParam2:val2
customNamedParam1:val1
Above tuple ('custom param1', 'custom param2', 'custom param3') is printed as is.
Omitting dict args:
function2("arg1",
*tupleCustomArgs,
param3="arg3",
param2="arg2",
dictCustomNamedArgs #omitting **
)
gives
dictCustomNamedArgs
^
SyntaxError: non-keyword arg after keyword arg

As an addition, you can also mix different ways of usage when calling kwargs functions:
def test(**kwargs):
print kwargs['a']
print kwargs['b']
print kwargs['c']
args = { 'b': 2, 'c': 3}
test( a=1, **args )
gives this output:
1
2
3
Note that **kwargs has to be the last argument

Here's a simple function that serves to explain the usage:
def print_wrap(arg1, *args, **kwargs):
print(arg1)
print(args)
print(kwargs)
print(arg1, *args, **kwargs)
Any arguments that are not specified in the function definition will be put in the args list, or the kwargs list, depending on whether they are keyword arguments or not:
>>> print_wrap('one', 'two', 'three', end='blah', sep='--')
one
('two', 'three')
{'end': 'blah', 'sep': '--'}
one--two--threeblah
If you add a keyword argument that never gets passed to a function, an error will be raised:
>>> print_wrap('blah', dead_arg='anything')
TypeError: 'dead_arg' is an invalid keyword argument for this function

kwargs are a syntactic sugar to pass name arguments as dictionaries(for func), or dictionaries as named arguments(to func)

Here is an example that I hope is helpful:
#! /usr/bin/env python
#
def g( **kwargs) :
print ( "In g ready to print kwargs" )
print kwargs
print ( "in g, calling f")
f ( **kwargs )
print ( "In g, after returning from f")
def f( **kwargs ) :
print ( "in f, printing kwargs")
print ( kwargs )
print ( "In f, after printing kwargs")
g( a="red", b=5, c="Nassau")
g( q="purple", w="W", c="Charlie", d=[4, 3, 6] )
When you run the program, you get:
$ python kwargs_demo.py
In g ready to print kwargs
{'a': 'red', 'c': 'Nassau', 'b': 5}
in g, calling f
in f, printing kwargs
{'a': 'red', 'c': 'Nassau', 'b': 5}
In f, after printing kwargs
In g, after returning from f
In g ready to print kwargs
{'q': 'purple', 'c': 'Charlie', 'd': [4, 3, 6], 'w': 'W'}
in g, calling f
in f, printing kwargs
{'q': 'purple', 'c': 'Charlie', 'd': [4, 3, 6], 'w': 'W'}
In f, after printing kwargs
In g, after returning from f
The key take away here is that the variable number of named arguments in the call translate into a dictionary in the function.

Keyword Arguments are often shortened to kwargs in Python. In computer programming,
keyword arguments refer to a computer language's support for function
calls that clearly state the name of each parameter within the
function call.
The usage of the two asterisk before the parameter name, **kwargs, is when one doesn't know how many keyword arguments will be passed into the function. When that's the case, it's called Arbitrary / Wildcard Keyword Arguments.
One example of this is Django's receiver functions.
def my_callback(sender, **kwargs):
print("Request finished!")
Notice that the function takes a sender argument, along with wildcard
keyword arguments (**kwargs); all signal handlers must take these
arguments.
All signals send keyword arguments, and may change those
keyword arguments at any time. In the case of request_finished, it’s
documented as sending no arguments, which means we might be tempted to
write our signal handling as my_callback(sender).
This would be wrong – in fact, Django will throw an error if you do
so. That’s because at any point arguments could get added to the
signal and your receiver must be able to handle those new arguments.
Note that it doesn't have to be called kwargs, but it needs to have ** (the name kwargs is a convention).

This is the simple example to understand about python unpacking,
>>> def f(*args, **kwargs):
... print 'args', args, 'kwargs', kwargs
eg1:
>>>f(1, 2)
>>> args (1,2) kwargs {} #args return parameter without reference as a tuple
>>>f(a = 1, b = 2)
>>> args () kwargs {'a': 1, 'b': 2} #args is empty tuple and kwargs return parameter with reference as a dictionary

In Java, you use constructors to overload classes and allow for multiple input parameters. In python, you can use kwargs to provide similar behavior.
java example: https://beginnersbook.com/2013/05/constructor-overloading/
python example:
class Robot():
# name is an arg and color is a kwarg
def __init__(self,name, color='red'):
self.name = name
self.color = color
red_robot = Robot('Bob')
blue_robot = Robot('Bob', color='blue')
print("I am a {color} robot named {name}.".format(color=red_robot.color, name=red_robot.name))
print("I am a {color} robot named {name}.".format(color=blue_robot.color, name=blue_robot.name))
>>> I am a red robot named Bob.
>>> I am a blue robot named Bob.
just another way to think about it.

Related

Pass dictionary directly as arguments of function [duplicate]

Let's imagine I have a dict :
d = {'a': 3, 'b':4}
I want to create a function f that does the exact same thing than this function :
def f(x, a=d['a'], b=d['b']):
print(x, a, b)
(Not necessarily print, but do some stuff with the variable and calling directly from their name).
But I would like to create this function directly from the dict, that is to say, I would like to have something that look likes
def f(x, **d=d):
print(x, a, b)
and that behaves like the previously defined function. The idea is that I have a large dictionary that contains defaults values for arguments of my function, and I would like not to have to do
def f(a= d['a'], b = d['b'] ...)
I don't know if it's possible at all in python. Any insight is appreciated !
Edit : The idea is to be able to call f(5, a=3).
Edit2 : The question is not about passing arguments stored in a dict to a function but to define a function whose arguments names and defaults values are stored in a dict.
You cannot achieve this at function definition because Python determines the scope of a function statically. Although, it is possible to write a decorator to add in default keyword arguments.
from functools import wraps
def kwargs_decorator(dict_kwargs):
def wrapper(f):
#wraps(f)
def inner_wrapper(*args, **kwargs):
new_kwargs = {**dict_kwargs, **kwargs}
return f(*args, **new_kwargs)
return inner_wrapper
return wrapper
Usage
#kwargs_decorator({'bar': 1})
def foo(**kwargs):
print(kwargs['bar'])
foo() # prints 1
Or alternatively if you know the variable names but not their default values...
#kwargs_decorator({'bar': 1})
def foo(bar):
print(bar)
foo() # prints 1
Caveat
The above can be used, by example, to dynamically generate multiple functions with different default arguments. Although, if the parameters you want to pass are the same for every function, it would be simpler and more idiomatic to simply pass in a dict of parameters.
Python is designed such that the local variables of any function can be determined unambiguously by looking at the source code of the function. So your proposed syntax
def f(x, **d=d):
print(x, a, b)
is a nonstarter because there's nothing that indicates whether a and b are local to f or not; it depends on the runtime value of the dictionary, whose value could change across runs.
If you can resign yourself to explicitly listing the names of all of your parameters, you can automatically set their default values at runtime; this has already been well covered in other answers. Listing the parameter names is probably good documentation anyway.
If you really want to synthesize the whole parameter list at run time from the contents of d, you would have to build a string representation of the function definition and pass it to exec. This is how collections.namedtuple works, for example.
Variables in module and class scopes are looked up dynamically, so this is technically valid:
def f(x, **kwargs):
class C:
vars().update(kwargs) # don't do this, please
print(x, a, b)
But please don't do it except in an IOPCC entry.
try this:
# Store the default values in a dictionary
>>> defaults = {
... 'a': 1,
... 'b': 2,
... }
>>> def f(x, **kwa):
# Each time the function is called, merge the default values and the provided arguments
# For python >= 3.5:
args = {**defaults, **kwa}
# For python < 3.5:
# Each time the function is called, copy the default values
args = defaults.copy()
# Merge the provided arguments into the copied default values
args.update(kwa)
... print(args)
...
>>> f(1, f=2)
{'a': 1, 'b': 2, 'f': 2}
>>> f(1, f=2, b=8)
{'a': 1, 'b': 8, 'f': 2}
>>> f(5, a=3)
{'a': 3, 'b': 2}
Thanks Olvin Roght for pointing out how to nicely merge dictionaries in python >= 3.5
How about the **kwargs trick?
def function(arg0, **kwargs):
print("arg is", arg0, "a is", kwargs["a"], "b is", kwargs["b"])
d = {"a":1, "b":2}
function(0., **d)
outcome:
arg is 0.0 a is 1 b is 2
This question is very interesting, and it seemed different people have their different own guess about what the question really want.
I have my own too. Here is my code, which can express myself:
# python3 only
from collections import defaultdict
# only set once when function definition is executed
def kwdefault_decorator(default_dict):
def wrapper(f):
f.__kwdefaults__ = {}
f_code = f.__code__
po_arg_count = f_code.co_argcount
keys = f_code.co_varnames[po_arg_count : po_arg_count + f_code.co_kwonlyargcount]
for k in keys:
f.__kwdefaults__[k] = default_dict[k]
return f
return wrapper
default_dict = defaultdict(lambda: "default_value")
default_dict["a"] = "a"
default_dict["m"] = "m"
#kwdefault_decorator(default_dict)
def foo(x, *, a, b):
foo_local = "foo"
print(x, a, b, foo_local)
#kwdefault_decorator(default_dict)
def bar(x, *, m, n):
bar_local = "bar"
print(x, m, n, bar_local)
foo(1)
bar(1)
# only kw_arg permitted
foo(1, a=100, b=100)
bar(1, m=100, n=100)
output:
1 a default_value
1 m default_value
1 100 100
1 100 100
Posting this as an answer because it would be too long for a comment.
Be careful with this answer. If you try
#kwargs_decorator(a='a', b='b')
def f(x, a, b):
print(f'x = {x}')
print(f'a = {a}')
print(f'b = {b}')
f(1, 2)
it will issue an error:
TypeError: f() got multiple values for argument 'a'
because you are defining a as a positional argument (equal to 2).
I implemented a workaround, even though I'm not sure if this is the best solution:
def default_kwargs(**default):
from functools import wraps
def decorator(f):
#wraps(f)
def wrapper(*args, **kwargs):
from inspect import getfullargspec
f_args = getfullargspec(f)[0]
used_args = f_args[:len(args)]
final_kwargs = {
key: value
for key, value in {**default, **kwargs}.items()
if key not in used_args
}
return f(*args, **final_kwargs)
return wrapper
return decorator
In this solution, f_args is a list containing the names of all named positional arguments of f. Then used_args is the list of all parameters that have effectively been passed as positional arguments. Therefore final_kwargs is defined almost exactly like before, except that it checks if the argument (in the case above, a) was already passed as a positional argument.
For instance, this solution works beautifully with functions such as the following.
#default_kwargs(a='a', b='b', d='d')
def f(x, a, b, *args, c='c', d='not d', **kwargs):
print(f'x = {x}')
print(f'a = {a}')
print(f'b = {b}')
for idx, arg in enumerate(args):
print(f'arg{idx} = {arg}')
print(f'c = {c}')
for key, value in kwargs.items():
print(f'{key} = {value}')
f(1)
f(1, 2)
f(1, b=3)
f(1, 2, 3, 4)
f(1, 2, 3, 4, 5, c=6, g=7)
Note also that the default values passed in default_kwargs have higher precedence than the ones defined in f. For example, the default value for d in this case is actually 'd' (defined in default_kwargs), and not 'not d' (defined in f).
You can unpack values of dict:
from collections import OrderedDict
def f(x, a, b):
print(x, a, b)
d = OrderedDict({'a': 3, 'b':4})
f(10, *d.values())
UPD.
Yes, it's possible to implement this mad idea of modifying local scope by creating decorator which will return class with overriden __call__() and store your defaults in class scope, BUT IT'S MASSIVE OVERKILL.
Your problem is that you're trying to hide problems of your architecture behind those tricks. If you store your default values in dict, then access to them by key. If you want to use keywords - define class.
P.S. I still don't understand why this question collect so much upvotes.
Sure...
hope this helps
def funcc(x, **kwargs):
locals().update(kwargs)
print(x, a, b, c, d)
kwargs = {'a' : 1, 'b' : 2, 'c':1, 'd': 1}
x = 1
funcc(x, **kwargs)

Give function defaults arguments from a dictionary in Python

Let's imagine I have a dict :
d = {'a': 3, 'b':4}
I want to create a function f that does the exact same thing than this function :
def f(x, a=d['a'], b=d['b']):
print(x, a, b)
(Not necessarily print, but do some stuff with the variable and calling directly from their name).
But I would like to create this function directly from the dict, that is to say, I would like to have something that look likes
def f(x, **d=d):
print(x, a, b)
and that behaves like the previously defined function. The idea is that I have a large dictionary that contains defaults values for arguments of my function, and I would like not to have to do
def f(a= d['a'], b = d['b'] ...)
I don't know if it's possible at all in python. Any insight is appreciated !
Edit : The idea is to be able to call f(5, a=3).
Edit2 : The question is not about passing arguments stored in a dict to a function but to define a function whose arguments names and defaults values are stored in a dict.
You cannot achieve this at function definition because Python determines the scope of a function statically. Although, it is possible to write a decorator to add in default keyword arguments.
from functools import wraps
def kwargs_decorator(dict_kwargs):
def wrapper(f):
#wraps(f)
def inner_wrapper(*args, **kwargs):
new_kwargs = {**dict_kwargs, **kwargs}
return f(*args, **new_kwargs)
return inner_wrapper
return wrapper
Usage
#kwargs_decorator({'bar': 1})
def foo(**kwargs):
print(kwargs['bar'])
foo() # prints 1
Or alternatively if you know the variable names but not their default values...
#kwargs_decorator({'bar': 1})
def foo(bar):
print(bar)
foo() # prints 1
Caveat
The above can be used, by example, to dynamically generate multiple functions with different default arguments. Although, if the parameters you want to pass are the same for every function, it would be simpler and more idiomatic to simply pass in a dict of parameters.
Python is designed such that the local variables of any function can be determined unambiguously by looking at the source code of the function. So your proposed syntax
def f(x, **d=d):
print(x, a, b)
is a nonstarter because there's nothing that indicates whether a and b are local to f or not; it depends on the runtime value of the dictionary, whose value could change across runs.
If you can resign yourself to explicitly listing the names of all of your parameters, you can automatically set their default values at runtime; this has already been well covered in other answers. Listing the parameter names is probably good documentation anyway.
If you really want to synthesize the whole parameter list at run time from the contents of d, you would have to build a string representation of the function definition and pass it to exec. This is how collections.namedtuple works, for example.
Variables in module and class scopes are looked up dynamically, so this is technically valid:
def f(x, **kwargs):
class C:
vars().update(kwargs) # don't do this, please
print(x, a, b)
But please don't do it except in an IOPCC entry.
try this:
# Store the default values in a dictionary
>>> defaults = {
... 'a': 1,
... 'b': 2,
... }
>>> def f(x, **kwa):
# Each time the function is called, merge the default values and the provided arguments
# For python >= 3.5:
args = {**defaults, **kwa}
# For python < 3.5:
# Each time the function is called, copy the default values
args = defaults.copy()
# Merge the provided arguments into the copied default values
args.update(kwa)
... print(args)
...
>>> f(1, f=2)
{'a': 1, 'b': 2, 'f': 2}
>>> f(1, f=2, b=8)
{'a': 1, 'b': 8, 'f': 2}
>>> f(5, a=3)
{'a': 3, 'b': 2}
Thanks Olvin Roght for pointing out how to nicely merge dictionaries in python >= 3.5
How about the **kwargs trick?
def function(arg0, **kwargs):
print("arg is", arg0, "a is", kwargs["a"], "b is", kwargs["b"])
d = {"a":1, "b":2}
function(0., **d)
outcome:
arg is 0.0 a is 1 b is 2
This question is very interesting, and it seemed different people have their different own guess about what the question really want.
I have my own too. Here is my code, which can express myself:
# python3 only
from collections import defaultdict
# only set once when function definition is executed
def kwdefault_decorator(default_dict):
def wrapper(f):
f.__kwdefaults__ = {}
f_code = f.__code__
po_arg_count = f_code.co_argcount
keys = f_code.co_varnames[po_arg_count : po_arg_count + f_code.co_kwonlyargcount]
for k in keys:
f.__kwdefaults__[k] = default_dict[k]
return f
return wrapper
default_dict = defaultdict(lambda: "default_value")
default_dict["a"] = "a"
default_dict["m"] = "m"
#kwdefault_decorator(default_dict)
def foo(x, *, a, b):
foo_local = "foo"
print(x, a, b, foo_local)
#kwdefault_decorator(default_dict)
def bar(x, *, m, n):
bar_local = "bar"
print(x, m, n, bar_local)
foo(1)
bar(1)
# only kw_arg permitted
foo(1, a=100, b=100)
bar(1, m=100, n=100)
output:
1 a default_value
1 m default_value
1 100 100
1 100 100
Posting this as an answer because it would be too long for a comment.
Be careful with this answer. If you try
#kwargs_decorator(a='a', b='b')
def f(x, a, b):
print(f'x = {x}')
print(f'a = {a}')
print(f'b = {b}')
f(1, 2)
it will issue an error:
TypeError: f() got multiple values for argument 'a'
because you are defining a as a positional argument (equal to 2).
I implemented a workaround, even though I'm not sure if this is the best solution:
def default_kwargs(**default):
from functools import wraps
def decorator(f):
#wraps(f)
def wrapper(*args, **kwargs):
from inspect import getfullargspec
f_args = getfullargspec(f)[0]
used_args = f_args[:len(args)]
final_kwargs = {
key: value
for key, value in {**default, **kwargs}.items()
if key not in used_args
}
return f(*args, **final_kwargs)
return wrapper
return decorator
In this solution, f_args is a list containing the names of all named positional arguments of f. Then used_args is the list of all parameters that have effectively been passed as positional arguments. Therefore final_kwargs is defined almost exactly like before, except that it checks if the argument (in the case above, a) was already passed as a positional argument.
For instance, this solution works beautifully with functions such as the following.
#default_kwargs(a='a', b='b', d='d')
def f(x, a, b, *args, c='c', d='not d', **kwargs):
print(f'x = {x}')
print(f'a = {a}')
print(f'b = {b}')
for idx, arg in enumerate(args):
print(f'arg{idx} = {arg}')
print(f'c = {c}')
for key, value in kwargs.items():
print(f'{key} = {value}')
f(1)
f(1, 2)
f(1, b=3)
f(1, 2, 3, 4)
f(1, 2, 3, 4, 5, c=6, g=7)
Note also that the default values passed in default_kwargs have higher precedence than the ones defined in f. For example, the default value for d in this case is actually 'd' (defined in default_kwargs), and not 'not d' (defined in f).
You can unpack values of dict:
from collections import OrderedDict
def f(x, a, b):
print(x, a, b)
d = OrderedDict({'a': 3, 'b':4})
f(10, *d.values())
UPD.
Yes, it's possible to implement this mad idea of modifying local scope by creating decorator which will return class with overriden __call__() and store your defaults in class scope, BUT IT'S MASSIVE OVERKILL.
Your problem is that you're trying to hide problems of your architecture behind those tricks. If you store your default values in dict, then access to them by key. If you want to use keywords - define class.
P.S. I still don't understand why this question collect so much upvotes.
Sure...
hope this helps
def funcc(x, **kwargs):
locals().update(kwargs)
print(x, a, b, c, d)
kwargs = {'a' : 1, 'b' : 2, 'c':1, 'd': 1}
x = 1
funcc(x, **kwargs)

Using named arguments as variables

I am using django but I think this question primarily belongs to Python itself.
I have something like:
def get(self, request, arg, *args, **kwargs):
if kwargs['m0'] == 'death':
if kwargs['m1'] == 'year':
result = Artists.objects.filter(death_year=arg)
elif kwargs['m1'] == 'month':
result = Artists.objects.filter(death_month=arg)
elif kwargs['m1'] == 'day':
result = Artists.objects.filter(death_day=arg)
elif kwargs['m0'] == 'birth':
if kwargs['m1'] == 'year':
result = Artists.objects.filter(birth_year=arg)
elif kwargs['m1'] == 'month':
result = Artists.objects.filter(birth_month=arg)
elif kwargs['m1'] == 'day':
result = Artists.objects.filter(birthh_day=arg)
Where death_year is a named argument that is a field in my model Artists representing a column in my database. The variables 'm0' and m1 are passed from the urlconf to my get function (it is actually a get method in my view class).
Can I control the name value of the variable death_year without using an if else if chain (i.e. make it death_month or birth_year)? Since I have many choices, I will have to use a ridiculously very long conditional chain that leads to this same line but with just a different named argument.
I strongly doubt that you should understand this whole problem to answer the question. The original question is simple: Can I use a named argument and its corresponding value as variables in Python?
From what I can make out you can construct the key and then pass in an arg to construct the dict, then include that in the filter
key = '%s_%s' % (kwargs['m0'], kwargs['m1'])
result = Artists.objects.filter(**{key: arg})
The basic and incredibly powerful idea in Python is that you can pass a list of positional arguments without writing args[0], args[1],... and/or a dict of keyword arguments without writing foo=kwargs["foo"], bar=kwargs["bar"],... by using * and ** as in func( *args, **kwargs)
A function can likewise be written to accept a list of positional args of arbitrary length, and any set of unmatched keyword arguments: def func( a, b, c=0, *args, **kwargs). (args and kwargs are not reserved words, just conventional variable names)
This example probably shows most of it in operation:
>>> def foo( a, b=0, c=0, *args, **kwargs):
... print( "a,b,c: ", a, b, c)
... print( args)
... print( kwargs)
...
>>> foo( *[1,2,3,4], **{"baz":42} )
a,b,c: 1 2 3
(4,)
{'baz': 42}
>>> foo( 1, b=2, **{"baz":42, "c":3} )
a,b,c: 1 2 3
()
{'baz': 42}
>>> foo( **{"baz":42, "c":3, "a":1, "zork":"?" } )
a,b,c: 1 0 3
()
{'zork': '?', 'baz': 42}
kwargs is a dict so if you want, you can use kwargs.keys() and all the other dict methods to introspect what the user actually passed and validate, parse, process etc. Django frequently uses kwargs.pop() to allow the fetching of arguments for the current function, while leaving other named arguments to propagate down a possibly deep set of nested function invocations until a routine near the bottom finds an optional keyword argument of its own.

Dynamically passing varying arguments to a predefined function [duplicate]

This question already has answers here:
What does ** (double star/asterisk) and * (star/asterisk) do for parameters?
(25 answers)
Closed 1 year ago.
What are the uses for **kwargs in Python?
I know you can do an objects.filter on a table and pass in a **kwargs argument.  
Can I also do this for specifying time deltas i.e. timedelta(hours = time1)?
How exactly does it work? Is it classified as 'unpacking'? Like a,b=1,2?
You can use **kwargs to let your functions take an arbitrary number of keyword arguments ("kwargs" means "keyword arguments"):
>>> def print_keyword_args(**kwargs):
... # kwargs is a dict of the keyword args passed to the function
... for key, value in kwargs.iteritems():
... print "%s = %s" % (key, value)
...
>>> print_keyword_args(first_name="John", last_name="Doe")
first_name = John
last_name = Doe
You can also use the **kwargs syntax when calling functions by constructing a dictionary of keyword arguments and passing it to your function:
>>> kwargs = {'first_name': 'Bobby', 'last_name': 'Smith'}
>>> print_keyword_args(**kwargs)
first_name = Bobby
last_name = Smith
The Python Tutorial contains a good explanation of how it works, along with some nice examples.
Python 3 update
For Python 3, instead of iteritems(), use items()
Unpacking dictionaries
** unpacks dictionaries.
This
func(a=1, b=2, c=3)
is the same as
args = {'a': 1, 'b': 2, 'c':3}
func(**args)
It's useful if you have to construct parameters:
args = {'name': person.name}
if hasattr(person, "address"):
args["address"] = person.address
func(**args) # either expanded to func(name=person.name) or
# func(name=person.name, address=person.address)
Packing parameters of a function
Use .items() instead of .iteritems() for python 3
def setstyle(**styles):
for key, value in styles.iteritems(): # styles is a regular dictionary
setattr(someobject, key, value)
This lets you use the function like this:
setstyle(color="red", bold=False)
Notes
kwargs is variable name used for keyword arguments, another variable name can be used. The important part is that it's a dictionary and it's unpacked with the double asterisk operator **.
Other iterables are unpacked with the single asterisk operator *
To prevent confusion, it's probably best to stick with the recognized variable names, kwargs and args, for dictionaries and other iterables respectively.
Resources
PEP 448: Additional Unpacking Generalizations
Real Python: Python args and kwargs: Demystified
What do * and ** before a variable name mean in a function signature?
kwargs is just a dictionary that is added to the parameters.
A dictionary can contain key, value pairs. And that are the kwargs. Ok, this is how.
The what for is not so simple.
For example (very hypothetical) you have an interface that just calls other routines to do the job:
def myDo(what, where, why):
if what == 'swim':
doSwim(where, why)
elif what == 'walk':
doWalk(where, why)
...
Now you get a new method "drive":
elif what == 'drive':
doDrive(where, why, vehicle)
But wait a minute, there is a new parameter "vehicle" -- you did not know it before. Now you must add it to the signature of the myDo-function.
Here you can throw kwargs into play -- you just add kwargs to the signature:
def myDo(what, where, why, **kwargs):
if what == 'drive':
doDrive(where, why, **kwargs)
elif what == 'swim':
doSwim(where, why, **kwargs)
This way you don't need to change the signature of your interface function every time some of your called routines might change.
This is just one nice example you could find kwargs helpful.
On the basis that a good sample is sometimes better than a long discourse I will write two functions using all python variable argument passing facilities (both positional and named arguments). You should easily be able to see what it does by yourself:
def f(a = 0, *args, **kwargs):
print("Received by f(a, *args, **kwargs)")
print("=> f(a=%s, args=%s, kwargs=%s" % (a, args, kwargs))
print("Calling g(10, 11, 12, *args, d = 13, e = 14, **kwargs)")
g(10, 11, 12, *args, d = 13, e = 14, **kwargs)
def g(f, g = 0, *args, **kwargs):
print("Received by g(f, g = 0, *args, **kwargs)")
print("=> g(f=%s, g=%s, args=%s, kwargs=%s)" % (f, g, args, kwargs))
print("Calling f(1, 2, 3, 4, b = 5, c = 6)")
f(1, 2, 3, 4, b = 5, c = 6)
And here is the output:
Calling f(1, 2, 3, 4, b = 5, c = 6)
Received by f(a, *args, **kwargs)
=> f(a=1, args=(2, 3, 4), kwargs={'c': 6, 'b': 5}
Calling g(10, 11, 12, *args, d = 13, e = 14, **kwargs)
Received by g(f, g = 0, *args, **kwargs)
=> g(f=10, g=11, args=(12, 2, 3, 4), kwargs={'c': 6, 'b': 5, 'e': 14, 'd': 13})
Motif: *args and **kwargs serves as a placeholder for the arguments that need to be passed to a function call
using *args and **kwargs to call a function
def args_kwargs_test(arg1, arg2, arg3):
print "arg1:", arg1
print "arg2:", arg2
print "arg3:", arg3
Now we'll use *args to call the above defined function
#args can either be a "list" or "tuple"
>>> args = ("two", 3, 5)
>>> args_kwargs_test(*args)
result:
arg1: two
arg2: 3
arg3: 5
Now, using **kwargs to call the same function
#keyword argument "kwargs" has to be a dictionary
>>> kwargs = {"arg3":3, "arg2":'two', "arg1":5}
>>> args_kwargs_test(**kwargs)
result:
arg1: 5
arg2: two
arg3: 3
Bottomline : *args has no intelligence, it simply interpolates the passed args to the parameters(in left-to-right order) while **kwargs behaves intelligently by placing the appropriate value # the required place
kwargs in **kwargs is just variable name. You can very well have **anyVariableName
kwargs stands for "keyword arguments". But I feel they should better be called as "named arguments", as these are simply arguments passed along with names (I dont find any significance to the word "keyword" in the term "keyword arguments". I guess "keyword" usually means words reserved by programming language and hence not to be used by the programmer for variable names. No such thing is happening here in case of kwargs.). So we give names
param1 and param2 to two parameter values passed to the function as follows: func(param1="val1",param2="val2"), instead of passing only values: func(val1,val2). Thus, I feel they should be appropriately called "arbitrary number of named arguments" as we can specify any number of these parameters (that is, arguments) if func has signature func(**kwargs)
So being said that let me explain "named arguments" first and then "arbitrary number of named arguments" kwargs.
Named arguments
named args should follow positional args
order of named args is not important
Example
def function1(param1,param2="arg2",param3="arg3"):
print("\n"+str(param1)+" "+str(param2)+" "+str(param3)+"\n")
function1(1) #1 arg2 arg3 #1 positional arg
function1(param1=1) #1 arg2 arg3 #1 named arg
function1(1,param2=2) #1 2 arg3 #1 positional arg, 1 named arg
function1(param1=1,param2=2) #1 2 arg3 #2 named args
function1(param2=2, param1=1) #1 2 arg3 #2 named args out of order
function1(1, param3=3, param2=2) #1 2 3 #
#function1() #invalid: required argument missing
#function1(param2=2,1) #invalid: SyntaxError: non-keyword arg after keyword arg
#function1(1,param1=11) #invalid: TypeError: function1() got multiple values for argument 'param1'
#function1(param4=4) #invalid: TypeError: function1() got an unexpected keyword argument 'param4'
Arbitrary number of named arguments kwargs
Sequence of function parameters:
positional parameters
formal parameter capturing arbitrary number of arguments (prefixed with *)
named formal parameters
formal parameter capturing arbitrary number of named parameters (prefixed with **)
Example
def function2(param1, *tupleParams, param2, param3, **dictionaryParams):
print("param1: "+ param1)
print("param2: "+ param2)
print("param3: "+ param3)
print("custom tuple params","-"*10)
for p in tupleParams:
print(str(p) + ",")
print("custom named params","-"*10)
for k,v in dictionaryParams.items():
print(str(k)+":"+str(v))
function2("arg1",
"custom param1",
"custom param2",
"custom param3",
param3="arg3",
param2="arg2",
customNamedParam1 = "val1",
customNamedParam2 = "val2"
)
# Output
#
#param1: arg1
#param2: arg2
#param3: arg3
#custom tuple params ----------
#custom param1,
#custom param2,
#custom param3,
#custom named params ----------
#customNamedParam2:val2
#customNamedParam1:val1
Passing tuple and dict variables for custom args
To finish it up, let me also note that we can pass
"formal parameter capturing arbitrary number of arguments" as tuple variable and
"formal parameter capturing arbitrary number of named parameters" as dict variable
Thus the same above call can be made as follows:
tupleCustomArgs = ("custom param1", "custom param2", "custom param3")
dictCustomNamedArgs = {"customNamedParam1":"val1", "customNamedParam2":"val2"}
function2("arg1",
*tupleCustomArgs, #note *
param3="arg3",
param2="arg2",
**dictCustomNamedArgs #note **
)
Finally note * and ** in function calls above. If we omit them, we may get ill results.
Omitting * in tuple args:
function2("arg1",
tupleCustomArgs, #omitting *
param3="arg3",
param2="arg2",
**dictCustomNamedArgs
)
prints
param1: arg1
param2: arg2
param3: arg3
custom tuple params ----------
('custom param1', 'custom param2', 'custom param3'),
custom named params ----------
customNamedParam2:val2
customNamedParam1:val1
Above tuple ('custom param1', 'custom param2', 'custom param3') is printed as is.
Omitting dict args:
function2("arg1",
*tupleCustomArgs,
param3="arg3",
param2="arg2",
dictCustomNamedArgs #omitting **
)
gives
dictCustomNamedArgs
^
SyntaxError: non-keyword arg after keyword arg
As an addition, you can also mix different ways of usage when calling kwargs functions:
def test(**kwargs):
print kwargs['a']
print kwargs['b']
print kwargs['c']
args = { 'b': 2, 'c': 3}
test( a=1, **args )
gives this output:
1
2
3
Note that **kwargs has to be the last argument
Here's a simple function that serves to explain the usage:
def print_wrap(arg1, *args, **kwargs):
print(arg1)
print(args)
print(kwargs)
print(arg1, *args, **kwargs)
Any arguments that are not specified in the function definition will be put in the args list, or the kwargs list, depending on whether they are keyword arguments or not:
>>> print_wrap('one', 'two', 'three', end='blah', sep='--')
one
('two', 'three')
{'end': 'blah', 'sep': '--'}
one--two--threeblah
If you add a keyword argument that never gets passed to a function, an error will be raised:
>>> print_wrap('blah', dead_arg='anything')
TypeError: 'dead_arg' is an invalid keyword argument for this function
kwargs are a syntactic sugar to pass name arguments as dictionaries(for func), or dictionaries as named arguments(to func)
Here is an example that I hope is helpful:
#! /usr/bin/env python
#
def g( **kwargs) :
print ( "In g ready to print kwargs" )
print kwargs
print ( "in g, calling f")
f ( **kwargs )
print ( "In g, after returning from f")
def f( **kwargs ) :
print ( "in f, printing kwargs")
print ( kwargs )
print ( "In f, after printing kwargs")
g( a="red", b=5, c="Nassau")
g( q="purple", w="W", c="Charlie", d=[4, 3, 6] )
When you run the program, you get:
$ python kwargs_demo.py
In g ready to print kwargs
{'a': 'red', 'c': 'Nassau', 'b': 5}
in g, calling f
in f, printing kwargs
{'a': 'red', 'c': 'Nassau', 'b': 5}
In f, after printing kwargs
In g, after returning from f
In g ready to print kwargs
{'q': 'purple', 'c': 'Charlie', 'd': [4, 3, 6], 'w': 'W'}
in g, calling f
in f, printing kwargs
{'q': 'purple', 'c': 'Charlie', 'd': [4, 3, 6], 'w': 'W'}
In f, after printing kwargs
In g, after returning from f
The key take away here is that the variable number of named arguments in the call translate into a dictionary in the function.
Keyword Arguments are often shortened to kwargs in Python. In computer programming,
keyword arguments refer to a computer language's support for function
calls that clearly state the name of each parameter within the
function call.
The usage of the two asterisk before the parameter name, **kwargs, is when one doesn't know how many keyword arguments will be passed into the function. When that's the case, it's called Arbitrary / Wildcard Keyword Arguments.
One example of this is Django's receiver functions.
def my_callback(sender, **kwargs):
print("Request finished!")
Notice that the function takes a sender argument, along with wildcard
keyword arguments (**kwargs); all signal handlers must take these
arguments.
All signals send keyword arguments, and may change those
keyword arguments at any time. In the case of request_finished, it’s
documented as sending no arguments, which means we might be tempted to
write our signal handling as my_callback(sender).
This would be wrong – in fact, Django will throw an error if you do
so. That’s because at any point arguments could get added to the
signal and your receiver must be able to handle those new arguments.
Note that it doesn't have to be called kwargs, but it needs to have ** (the name kwargs is a convention).
This is the simple example to understand about python unpacking,
>>> def f(*args, **kwargs):
... print 'args', args, 'kwargs', kwargs
eg1:
>>>f(1, 2)
>>> args (1,2) kwargs {} #args return parameter without reference as a tuple
>>>f(a = 1, b = 2)
>>> args () kwargs {'a': 1, 'b': 2} #args is empty tuple and kwargs return parameter with reference as a dictionary
In Java, you use constructors to overload classes and allow for multiple input parameters. In python, you can use kwargs to provide similar behavior.
java example: https://beginnersbook.com/2013/05/constructor-overloading/
python example:
class Robot():
# name is an arg and color is a kwarg
def __init__(self,name, color='red'):
self.name = name
self.color = color
red_robot = Robot('Bob')
blue_robot = Robot('Bob', color='blue')
print("I am a {color} robot named {name}.".format(color=red_robot.color, name=red_robot.name))
print("I am a {color} robot named {name}.".format(color=blue_robot.color, name=blue_robot.name))
>>> I am a red robot named Bob.
>>> I am a blue robot named Bob.
just another way to think about it.

Calling a Python function with *args,**kwargs and optional / default arguments

In Python I can define a function as follows:
def func(kw1=None,kw2=None,**kwargs):
...
In this case, I can call func as:
func(kw1=3,kw2=4,who_knows_if_this_will_be_used=7,more_kwargs=Ellipsis)
I can also define a function as:
def func(arg1,arg2,*args):
...
which can be called as
func(3,4,additional,arguments,go,here,Ellipsis)
Finally, I can combine the two forms
def func(arg1,arg2,*args,**kwargs):
...
But, what does not work is calling:
func(arg1,arg2,*args,kw1=None,kw2=None,**kwargs): #SYNTAX ERROR (in Python 2 only, apparently this works in Python 3)
...
My original thought was that this was probably because a function
def func(arg1,arg2,*args,kw1=None):
...
can be called as
func(1,2,3) #kw1 will be assigned 3
So this would introduce some ambiguity as to whether 3 should be packed into args or kwargs. However, with Python 3, there is the ability to specify keyword only arguments:
def func(a,b,*,kw=None): # can be called as func(1,2), func(1,2,kw=3), but NOT func(1,2,3)
...
With this, it seems that there is no syntactic ambiguity with:
def func(a,b,*args,*,kw1=None,**kwargs):
...
However, this still brings up a syntax error (tested with Python3.2). Is there a reason for this that I am missing? And, is there a way to get the behavior I described above (Having *args with default arguments) -- I know I can simulate that behavior by manipulating the kwargs dictionary inside the function.
You can do that in Python 3.
def func(a,b,*args,kw1=None,**kwargs):
The bare * is only used when you want to specify keyword only arguments without accepting a variable number of positional arguments with *args. You don't use two *s.
To quote from the grammar, in Python 2, you have
parameter_list ::= (defparameter ",")*
( "*" identifier [, "**" identifier]
| "**" identifier
| defparameter [","] )
while in Python 3, you have
parameter_list ::= (defparameter ",")*
( "*" [parameter] ("," defparameter)*
[, "**" parameter]
| "**" parameter
| defparameter [","] )
which includes a provision for additional parameters after the * parameter.
UPDATE:
Latest Python 3 documentation here.
If you want to do a mixture of both remember that *args and **kwargs must be the last parameters specified.
def func(arg1,arg2,*args,kw1=None,kw2=None,**kwargs): #Invalid
def func(arg1,arg2,kw1=None,kw2=None,*args,**kwargs): #Valid
The comments seem to be based on mixing up how a function definition is constructed compared to how the arguments provided are assigned back to the parameters specified in the definition.
This is the definition of this function which has 6 parameters.
It is called by passing named and unnamed arguments to it in a function call.
For this example...
When an argument is named when calling the function it can be provided out of order.
arg1 and arg2 are mandatory parameters and if not passed to the function as named arguments, then they must be assigned in order from the provided unnamed arguments.
kw1 and kw2 have default values provided in the function definition so they are not mandatory, but if not provided for as named arguments they will take any available values from the remaining provided unnamed arguments.
Any unnamed arguments left over are provided to the function in an array called args
Any named arguments that do not have a corresponding parameter name in the function definition are provided to the function call in a dictionary called kwargs.
Clear and concise:
In Python 3.5 or greater:
def foo(a, b=3, *args, **kwargs):
defaultKwargs = { 'c': 10, 'd': 12 }
kwargs = { **defaultKwargs, **kwargs }
print(a, b, args, kwargs)
# Do something else
foo(1) # 1 3 () {'c': 10, 'd': 12}
foo(1, d=5) # 1 3 () {'c': 10, 'd': 5}
foo(1, 2, 4, d=5) # 1 2 (4,) {'c': 10, 'd': 5}
Note: you can use
In Python 2
kwargs = merge_two_dicts(defaultKwargs, kwargs)
In Python 3.5
kwargs = { **defaultKwargs, **kwargs }
In Python 3.9
kwargs = defaultKwargs | kwargs # NOTE: 3.9+ ONLY
If you are looking to do that in Python 2, I have found a workaround explained in this post, using a decorator.
This decorator assigns default kwarg values if they are not strictly defined.
from functools import wraps
def force_kwargs(**defaultKwargs):
def decorator(f):
#wraps(f)
def g(*args, **kwargs):
new_args = {}
new_kwargs = defaultKwargs
varnames = f.__code__.co_varnames
new_kwargs.update(kwargs)
for k, v in defaultKwargs.items():
if k in varnames:
i = varnames.index(k)
new_args[(i, k)] = new_kwargs.pop(k)
# Insert new_args into the correct position of the args.
full_args = list(args)
for i, k in sorted(new_args.keys()):
if i <= len(full_args):
full_args.insert(i, new_args.pop((i, k)))
else:
break
# re-insert the value as a key-value pair
for (i, k), val in new_args.items():
new_kwargs[k] = val
return f(*tuple(full_args), **new_kwargs)
return g
return decorator
Result
#force_kwargs(c=7, z=10)
def f(a, b='B', c='C', d='D', *args, **kw):
return a, b, c, d, args, kw
# a b c d args kwargs
f('r') # 'r', 'B', 7, 'D', (), {'z': 10}
f(1, 2, 3, 4, 5) # 1, 2, 7, 3, (4,5), {'z': 10}
f(1, 2, 3, b=0, c=9, f='F', z=5) # 1, 0, 9, 2, (3,), {'f': 'F', 'z': 5}
Variant
If you want to use the default values as written in the function definition, you could access the argument default values using f.func_defaults, which lists the default values. You would have to zip them with the end of the f.__code__.varnames to match these default values with the variable names.

Categories