Optional Parameters in **kwargs - python

I am not able to handle to pass optional parameters in python **kwargs
def ExecuteyourQuery(self, queryStatement, *args, **kwargs):
if self.cursorOBJ is not None:
resultOBJ = self.cursorOBJ.execute(queryStatement, *args,**kwargs)
self.resultsVal = resultOBJ.fetchall()
The below statement works fine when I am calling the function
ExecuteyourQuery('select * from item_table where x = :x and y:y', x, y)
But when I give an extra argument which is not mentioned in the query, like
ExecuteyourQuery('select * from item_table where x = :x and y:y', x, y, z)
It returns 0 as output

When using args as the last parameter of your function, you can pass any number of arguments after the formal arguments, when existing. Args is a tuple.
def my_method(farg, *args):
print('FARG: ', farg)
print('ARGS: ', args)
my_method('Formal Argument', 1, 2, 3)
When using kwargs as the last parameter of your function, you can pass any number of named arguments after the formal arguments, when existing. Kwargs is a dictionary.
def my_method(farg, **kwargs):
print('FARG: ', farg)
print('KWARGS: ', kwargs)
my_method('Formal Argument', kwarg_1 = 1, kwarg_2 = 2, kwarg_3 = 3)
When using both args and kwargs as the last parameteres of your function, you can pass any number of arguments (that will be mapped to args) and named arguments (that will be mapped to kwargs) after the formal arguments, when existing.
def my_method(farg, *args, **kwargs):
print('FARG: ', farg)
print('ARGS: ', args)
print('KWARGS: ', kwargs)
my_method('Formal Argument', 1, 2, 3, kwarg_1 = 1, kwarg_2 = 2, kwarg_3 = 3)
Try this out and see the results in your console, hopefully it will help you solve your original problem :)

another way to do this is by setting a default value for a parameter
def method(one, two, three=3):
print(one)
print(two)
if three != 3: # don't have to use it like this but it is a default value
print(three)
this set a default value if the parameter is not filled
if it is filled it will overrule the default value and use that
method(11, 22) # prints first two parameters
method(23, 54, 89) # prints all three
Not sure if this is what your looking for but it is another way

Related

Retrieving function arguments from *args and **kwargs

Let's say I have a function f() which I know accepts 1 argument, action, followed by a variable number of arguments.
Depending on the initial action value, the function expects a different set of following arguments, e.g. for action 1 we know we must have 3 extra arguments p1, p2 and p3. Depending on how the function was called, these args can be either in args or `kwargs.
How do I retrieve them?
def f(action, *args, **kwargs):
if action==1:
#we know that the function should have 3 supplementary arguments: p1, p2, p3
#we want something like:
#p1 = kwargs['p1'] OR args[0] OR <some default> (order matters?)
#p1 = kwargs['p1'] OR args[0] OR <some default>
#p1 = kwargs['p1'] OR args[0] OR <some default>
Note that:
f(1, 3, 4, 5)
f(1,p1=3, p2=4, p3=5)
f(1, 2, p2=4, p3=5)
will place the different p1, p2, p3 parameters in either args or kwargs. I could try with nested try/except statements, like:
try:
p1=kwargs['p1']
except:
try:
p1=args[0]
except:
p1=default
but it does not feel right.
I would call a sub-function with a defined argument list within f:
def f(action, *args, **kwargs):
if action == 1:
f_1(*args, **kwargs)
...
def f_1(p1, p2, p3):
# now you know the args
Of course, this raises the question why you need the over-all function, but let's assume you have a reason for that ;). Else, you could also have a dictionary:
funcs = {1: f_1, 2: ....}
Then you can call the correct function with individual arguments as
funcs[action](p1, p2, p3)
I feel you were quite close to the answer on your question in out of itself.
You can do something like this:
def f(action, *args, **kwargs):
if action==1:
p1=kwargs.get('p1') or args[0] if len(args)>0 else 'default'
...
The order does matter. In this case if you the key arguments would take priority over positional ones.
Here are some input examples --> value of p1 in the function:
f(1,10)-->10
f(1,2,20)-->2
f(1,p1=10)-->10
f(1,10,p1=2)-->2
f(1,p3=20)-->'default'
You can try with, using OrderedDict:
from collections import OrderedDict
def f(action, *args, **kwargs):
params = OrderedDict({
'p1': 'default',
'p2': 'default',
'p3': 'default',
})
if action == 1:
for index, param in enumerate(params.keys()):
if index < len(args):
params[param] = kwargs[param] if param in kwargs else args[index]
else:
params[param] = kwargs[param] if param in kwargs else params[param]
# Do something with `params`.
f(1, 3, 4, 5)
f(1, p1=3, p2=4, p3=5)
f(1, 2, p2=4, p3=5)
If you need more parameters, just add them to the ordered dictionary.

Compact way to pass same value to arguments

When I have a function with bunch of optional arguments
def function_name(arg1=0, arg2=0, arg3=0, arg4=0, ...):
.....doing anything
and I want to pass same value to some of them
function_name(arg1=1, arg3=1, arg6=1)
Is there a more compact way to do it?
so I don't have to keep copying =value and filling up the line.
After several helpful replies I think I came to the answer I was looking for:
def myargs(value, *args):
kargs = {}
for arg in args:
kargs[arg] = value
return kargs
function_name(**myargs(1, 'arg1', 'arg3', 'arg6'))
Thanks guys, sorry if I was bad at explaining what I needed.
I think what you are wanting to do is keyword argument unpacking. You can pass a dictionary to the function and it will unpack the arguments you have included. Anything not included uses the default values.
def test(w=0, x=0, y=0, z=0):
return w+x+y+z
kwargs_1 = {'y': 1}
kwargs_2 = {'x': 2, 'z': 3}
test(**kwargs_1)
# returns:
1
test(**kwargs_2)
# returns:
5
You can use default arguments:
def func(arg1, arg2, def_arg1="1", def_arg2="2"):
pass
You can just use **kwargs
def function_name(arg, argOpt1=0, argOpt2=0, **kwargs):
pass
kwargs = {"argOpt1" : 123, "argOpt2" : 234}
function_name('argument1', kwargs)
Look at this
and this
If the arguments that are to have the same value are contiguous, then:
def function_name(arg1=0,arg2=0,arg3=0,arg4=0):
print(arg1, arg2, arg3, arg4)
function_name(2, *[1] * 3)
Prints:
2 1 1 1
If you didn't write that function, and you can't change its signature, you can pass the right number of arguments that way :
function_name(*(0,) * function_name.__code__.co_argcount)
It will pass the same value (in that case 0) to all the arguments the function expects.
If you need to pass only 10 arguments for instance, you can write :
function_name(*(0,) * 10)
If you want to target specific arguments by their position and not their names, you can use this :
import inspect
def func(a, b, c=None, d='foo', e=False):
print(a, b, c, d, e)
def fill_args(fun, value, arg_numbers):
return {
name: value
for name in (
tuple(inspect.signature(fun).parameters)[i]
for i in arg_numbers
)
}
if __name__ == '__main__':
func(**fill_args(func, 0, (0, 1, 2)))
func(**fill_args(func, 'bar', (0, 1, 4)))
func(**fill_args(func, True, (0, 1, 3)))

Pass a list of functions with their corresponding parameters to another function

I am struggling to pass a list of functions with a list of corresponding parameters. I also checked here, but it wasn't very helpful. for example (a naive approach which doesn't work):
def foo(data, functions_list, **kwarg):
for func_i in functions_list:
print func_i(data, **kwarg)
def func_1(data, par_1):
return some_function_1(data, par_1)
def func_2(data, par_2_0, par_2_1):
return some_function_2(data, par_2_0, par_2_1)
foo(data, [func_1, func_2], par_1='some_par', par_2_0=5, par_2_1=11)
Importantly, par_1 cannot be used in func_2, so each function consumes a unique set of parameters.
You could use the function's name as the keyword arguments. When indexing kwargs, you'd use func_i.__name__ as the key.
def foo(data, function_list, **kwargs):
for func_i in function_list:
print(func_i(data, kwargs[func_i.__name__]))
And now,
foo(data, [func_1, func_2], func_1='some_par', func_2=[5, 11])
You could use inspect.getargspec (I assume you use Python 2, you shouldn't use that function in Python 3 because it has been deprecated) to find out which argument names a function has and build a new dictionary based on those:
import inspect
def foo(data, functions_list, **kwargs):
for func_i in functions_list:
newkwargs = {name: kwargs[name]
for name in inspect.getargspec(func_i).args
if name in kwargs}
print(func_i(data, **newkwargs))
def func_1(data, par_1):
return data, par_1
def func_2(data, par_2_0, par_2_1):
return data, par_2_0, par_2_1
>>> data = 10
>>> foo(data, [func_1, func_2], par_1='some_par', par_2_0=5, par_2_1=11)
(10, 'some_par')
(10, 5, 11)
But a better way would be to simply associate parameters with functions that doesn't rely on introspection.
If you want to keep the foo function with that exact same declaration and you don't mind each function receiving the whole set of parameters you could do it like this:
You just need to add to each 'my_*' function the **kwargs parameter.
def foo(data, functions_list, **kwargs):
for my_function in functions_list:
print(my_function(data, **kwargs))
def my_sum(a, b, **kwargs):
return a + b
def my_sub(a, c, **kwargs):
return a - c
foo(0, [my_sum, my_sub], b=3, c=10)
Python automatically parses kwargs setting the b and c parameters where it has the value.
Another approach can be like this:
def foo(data, function_list, **kwargs):
function_dict = {
"func_1": func_1,
"func_2": func_2
}
for func_i in function_list:
print function_dict[func_i](data, **kwargs)
def func_1(data, **arg):
filtered_argument = {key: value for key, value in arg.items() if key.startswith('par_1')}
return list([data, filtered_argument])
def func_2(data, **arg):
filtered_argument = {key: value for key, value in arg.items() if key.startswith('par_2_')}
return list([data, filtered_argument])
data = [1,2,3]
foo(data, ['func_1', 'func_2'], par_1='some_par', par_2_0=5, par_2_1=11)
Output:
[[1, 2, 3], {'par_1': 'some_par'}]
[[1, 2, 3], {'par_2_0': 5, 'par_2_1': 11}]
I am sure that you can improvise your current code as it gets ugly in this way.
I like #COLDSPEED's approach, but want to present yet another solution. Pass always 3 values: function, args, keyword args:
Usage:
foo(
func_1, ('some_par',), {},
func_2, (5, 11), {},
)
Implementation (Python3 syntax):
def foo(*args3):
while args3:
func, args, kwargs, *args3 = args3
func(*args, **kwargs)
An approach would be making the 3rd argument of foo a positional argument and pass in a list of args with functions list:
def foo(data, functions_list, args):
for func, arg in zip(functions_list, args):
print(func(data, arg))
def func1(data, par_1):
return 'func1 called with {}'.format(par_1)
def func2(data, par_2):
return 'func2 called with {}'.format(par_2)
foo('some_data', [func1, func2],
[
{'par_1_1': 11, 'par_1_2': 12},
{'par_2_1': 21, 'par_2_2': 22}
])
zip() is used to map each function with the corresponding args.
Output:
func1 called with {'par_1_1': 11, 'par_1_2': 12}
func2 called with {'par_2_1': 21, 'par_2_2': 22}
You can do it something like that, "close" each parameters for function in a list item and then let "foo" split it backwards:
def foo(data, functions_list, kwarg):
for func_i, args in zip(functions_list, kwarg):
func_i(data, **args)
def func_1(data, par_1):
print("func_1 %s %s" % (data, par_1))
def func_2(data, par_2_0, par_2_1):
print("func_2 %s "
"%s %s" % (data, par_2_0, par_2_1))
data = "Some Data"
foo(data, [func_1, func_2], [{"par_1":'some_par'}, {"par_2_0":5, "par_2_1":11}])

What does this to in python super().__init__(**kwargs)

I know that super is used to call the init method in the superclass, I'm having trouble understanding what kwargs does I know it takes key arguments
what does it do here?
class LoginScreen(GridLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.cols = 2
self.add_widget(Label(text = "Username: "))
self.username = TextInput(multiline = False)
self.add_widget(self.username)
self.add_widget(Label(text="Password: "))
self.username = TextInput(multiline=False, password=True)
self.add_widget(self.username)
self.add_widget(Label(text="Two Factor Auth: "))
self.tffa = TextInput(multiline=False, password=True)
self.add_widget(self.tffa)
def __init__(self, **kwargs): packs all of the keyword arguments used in any given call to __init__ into a dict
super().__init__(**kwargs): expands them into keyword arguments again.
It's like a wildcard for function parameters. It can be a lazy way to give the subclass the same parameter signature as the parent without bothering to type all of the possible keyword parameters in again.
Just grab them as a blob and shovel them off to the parent to figure out.
For example you put this :
x = LoginScreen(size=1, blahblah=2, something=3)
We have now:
>>> print(kwargs)
{'size': 1, 'blahblah': 2, 'something': 3}
So if it reaches the following line: super().__init__(**kwargs)
it will be equal to that : super().__init__(size=1, blahblah=2, something=3)
Becarefully: if you didn't put double asterisks "**" it will be equal to one argument as key:
`super().__init__({'size': 1, 'blahblah': 2, 'something': 3})`
And you can also use it like that:
options = [1,2,3]
def func(first=None, second=None, last=None):
print("first arg:", first)
print("second arg:", second)
print("third arg:", last)
func(*options)
Here we use one asterisk since this is a list not a dict so that means expand the options list for each argument, the output will be:
first arg: 1
second arg: 2
third arg: 3
But if we call options without the asterisk.
func(options)
See what's gonna happen:
first arg: [1, 2, 3]
second arg: None
third arg: None
The samething with kwargs except they go like that:
fuction(key1=value1, key2=value2, key3=value3, ...)

How to pass named variables to a function in tupled form Python

I have a class with a method:
class Learner:
def fit(x,y,iterations=1,subsample_proportion=0.1):
etc...
def predict(X):
etc..
And a function:
def error(learner,learner_args,X,Y):
learner.fit(learner_args)
Y_pred = learner.predict(X)
etc...
How do I make the learner_args tuple to pass into this function in Python?
Right now I have:
learner = ada_boost.AdaBoost
learner_args = (train_x,train_y,4,0.2)
And it doesn't work.
Also, is there a way to pass named parameters to a function call?
so, for instance, in my function, I would do:
learner_args = (train_x,train_y,subsample_proportion=0.2)
Ignoring iterations. Is there a way to do this in Python? (internal to the language...not by using a dictionary and testing for values everywhere)
Use ** before a dictionary. Example:
def f(a,b, c=0, d='a'):
print a,b,c,d
kwargs = {'a' = 1, 'b' = 2}
f(**kwargs)
>>> 1 2 0 a
edit:
According to your comments, you might want something like:
args = ('first argument', 'second argument')
kwargs = {'c':'named argument c', 'd':'named argument d'}
f(*args, **kwargs)
>>> 'first argument', 'second argument', 'named argument c', 'named argument d'
learner_args is fine; you just need to pass it properly.
learner.fit(*learner_args)

Categories

Resources