syntax error: non-keyword arg after keyword arg - python

I'm using Python 2.7.13 in spyder.
def test(a,b,c='c',*args):
for item in args:
print item
This function definition is valid in Python 2.7, but as soon as I try to pass in args it gives me the non-keyword arg after keyword arg error:
test(1,2,c='c',10,11)
Gives this:
non-keyword arg after keyword arg
But this:
test(1,2,3,4,5)
Is working.
I'm not sure what's the issue here since putting the *args bfore c='c'
def test(a,b,*args,c='c'):
for item in args:
print item
This gives me an error in the function definition.
The above code is just a dummy example the original code looks like the following:
def export_plot_as_mat(fname, undersamp, undersamp_type, n_comp, b_s, n_iter, fit_alg, transf_alg, alpha_train, alpha_test, export_info=False, *args):
info = ('undersampling=' + str(undersamp) + ' undersampling_type=' +str(undersamp_type) +
' n_comp=' + str(n_comp) + ' batch_size=' + str(b_s) +
' n_iter=' + str(n_iter) + ' fit_alg=' + str(fit_alg) +
' transform_alg=' + str(transf_alg) + ' alpha_train=' +
str(alpha_train) + ' alpha_test=' + str(alpha_test))
d = [(str(args[i]), args[i]) for i in range(len(args))]
if export_info:
d.append('info',info)
sp.io.savemat(fname + '.mat', d)
I want to have the option to export the parameters used to build the data I'm exporting.

The definition is fine, since c can be specified positionally. The call is the problem; you specified a keyword argument before another positional argument.
Python 2.x doesn't have a way to define keyword-only arguments.

This is an interesting side case of how Python 2.x does argument parsing. Roughly, Python has some logic for how to "match up" the arguments you pass to a function with the arguments that it is expecting, and this logic changed in Python 3.
The easiest way to get what you want is to accept **kwargs instead of specifying c=0, and do the default argument manually.

A couple things here.
When change the c = 'c' in your test() to just 'c'
also u can put your last to arguments in a list to print them on the same line. or leave them as is to print them in separate lines.
def test(a,b,c='c',*args):
for item in args:
print item
test(1,2,'c',[10,11])
result:
[10, 11]
For the argument c = 'c' you can pass anything you want there and interact with c:
Take this example:
def test(a,b,c='c',*args):
print c
for item in args:
print item
test(1,2,'g',10,11)
Result:
g
10
11

Related

Error catching - incorrect number of arguments requested when calling the function

I get an interesting problem:
Let's take such a function for example:
def SumNumbers(a,b,c,d,e,f):
try:
print("Marta: ",
a,"+",b,'+',c,'+',d,'+',e,'+',f,
'=',
a + b + c + d + e + f)
except TypeError:
print("Enter the values for the 6 parameters of the program")
How we can handling this error in this case:
SumNumbers(1,2,3)
and in this case:
SumNumbers(1,2,3,4,5,5,6,77,7,8,88,8,8,8,8)
Of course, I mean handling this bug in the function body :)
My attempt to intercept a TypeError is unfortunately invalid :(
I think the best thing to do would be to use a decorator, your exception is happening on the function call, not when you try the print. That is why you are not excepting the error as your error happens before your try statement. Here is an example:
def typeErrorException(func):
def inner(*nums):
try:
func(*nums)
except TypeError:
print("Invalid input")
return inner
#typeErrorException
def SumNumbers(a,b,c,d,e,f):
print("Marta: ",
a,"+",b,'+',c,'+',d,'+',e,'+',f,
'=',
a + b + c + d + e + f)
SumNumbers(1,2,3,4,5,6,7)
Your decorator is being called first before your function, trying your function with the given arguments. This means that you don't have to explicitly try, except every time you call the function.
More information on decorators: https://realpython.com/primer-on-python-decorators/
Use *args:
def SumNumbers(*args):
if len(args) != 6:
print("Enter the values for the 6 parameters of the program")
return
print(f"Marta: {' + '.join(str(i) for i in args)} = {sum(args)}")

Passing many variables as one variable in python

I have a list of variables that I want to send to my function. (so the function works based on the values on those variables).
One way is to pass each variable separately in the function like this:
def my_function(var1, var2, var3, var4, ..., varn):
output = var1 + var2 + var3 + var4 + .... + varn
However, I wonder if I can write such a thing:
def my_function(parameters):
output = parameters.var1 + parameters.var2 + ... + parameters.varn
That is, somehow is there any way to wrap all variables in one variable, and then call them like this?
I know the above python codes are not correct, I just want to express my question.
Thanks in advance
There are many options. You have to determine which way fits your case.
Option 1. Getting multiple arguments by a single asterisk
def my_function(*args):
output = sum(args)
# SAME WITH
# output = args[0] + args[1] + ... + args[n]
#
# PASSING ARGUMENTS EXAMPLE
# my_function(10, 20, 10, 50)
Option 2. Getting keyword arguments by double asterisk
def my_function(**kwargs):
output = sum(kwargs.values())
# SAME WITH
# output = kwargs["var0"] + kwargs["var1"] + ... + kwargs["varn"]
#
# PASSING ARGUMENTS EXAMPLE
# my_function(var0=10, var1=20, var2=15)
Option 3. Getting an argument as a list
def my_function(list_arg):
output = sum(list_arg)
# SAME WITH
# output = list_arg[0] + list_arg[1] + ... + list_arg[n]
#
# PASSING ARGUMENTS EXAMPLE
# my_function([1, 10, 3, -10])
Option 4. Getting an argument as a dictionary
def my_function(dict_arg):
output = sum(dict_arg.values())
# SAME WITH
# output = kwargs["var0"] + kwargs["var1"] + ... + kwargs["varn"]
#
# PASSING ARGUMENTS EXAMPLE
# my_function({"var0":5, "var1":10, "var2":3})

Optional arguments in nested functions in Python

Is it possible for one function to take as an argument the name of one of the optional arguments of a second function then call the second function with the optional argument set to the value of some variable in the first function?
Code (that obviously doesn't work)
def foo(a=1,b=2,c=3):
d = a + b + c
return d
def bar(variable):
z = get_user_input()
e = foo(variable = z)
return e
print(bar(a))
The desired result is for bar to call foo(a=z) and print whatever z+2+3 is. Of course Python doesn't know what (a) is here. My guess is that I can somehow reference the list of arguments of foo() , but I am stumped as to how you might do that.
Maybe try the code snippet below
def foo(a=1,b=2,c=3):
d = a + b + c
return d
def bar(variable: str):
z = int(input())
e = foo(**{variable: z})
return e
# variable name should be defined as string
print(bar("a"))
The ** parses all arbitrary arguments on dict, in this case is a. Be careful tho, as if passing wrong variable name (differ from a, b or c) will result raising error.

Default Initialization of Starred Variables within the Definition of a Function

It is well-known that in order to set a default value to a variable within a function in Python, the following syntax is used:
def func(x = 0):
if x == 0:
print("x is equal to 0")
else:
print("x is not equal to 0")
So if the function is called as such:
>>> func()
It results in
'x is equal to 0'
But when a similar technique is used for starred variables, for example,
def func(*x = (0, 0)):
it results in a syntax error. I've tried switching up the syntax by also doing (*x = 0, 0) but the same error is encountered. Is it possible to initialize a starred variable to a default value?
star variables are non standard variables that are meant to allow functions with arbitrary length
*variables is a tuple with all positional arguments (This is usually named args)
**variables is a dictionary with all named arguments (This is usually named kwargs )
They would always be there, just empty if none is provided. You could test if a value is in the dictionary or tuple depending on what type of argument and initialize it.
def arg_test(*args,**kwargs):
if not args:
print "* not args provided set default here"
print args
else:
print "* Positional Args provided"
print args
if not kwargs:
print "* not kwargs provided set default here"
print kwargs
else:
print "* Named arguments provided"
print kwargs
#no args, no kwargs
print "____ calling with no arguments ___"
arg_test()
#args, no kwargs
print "____ calling with positional arguments ___"
arg_test("a", "b", "c")
#no args, but kwargs
print "____ calling with named arguments ___"
arg_test(a = 1, b = 2, c = 3)
The starred variable has a value of an empty tuple () by default. While it's not possible to change that default value due to how starred parameters work (tl;dr: Python assigns un-starred parameters, if any are available and collects the rest inside a tuple; you can read more about them for example in the relevant PEP 3132: https://www.python.org/dev/peps/pep-3132/) you could implement a check at the beginning of the function to find out if x is an empty tuple and then change it accordingly. Your code would look something like this:
def func(*x):
if x == (): # Check if x is an empty tuple
x = (0, 0)
if x == 0:
print("x is equal to 0")
else:
print("x is not equal to 0")

What does asterisk * mean in Python? [duplicate]

This question already has answers here:
What does ** (double star/asterisk) and * (star/asterisk) do for parameters?
(25 answers)
Closed 9 years ago.
Does * have a special meaning in Python as it does in C? I saw a function like this in the Python Cookbook:
def get(self, *a, **kw)
Would you please explain it to me or point out where I can find an answer (Google interprets the * as wild card character and thus I cannot find a satisfactory answer).
See Function Definitions in the Language Reference.
If the form *identifier is
present, it is initialized to a tuple
receiving any excess positional
parameters, defaulting to the empty
tuple. If the form **identifier is
present, it is initialized to a new
dictionary receiving any excess
keyword arguments, defaulting to a new
empty dictionary.
Also, see Function Calls.
Assuming that one knows what positional and keyword arguments are, here are some examples:
Example 1:
# Excess keyword argument (python 2) example:
def foo(a, b, c, **args):
print "a = %s" % (a,)
print "b = %s" % (b,)
print "c = %s" % (c,)
print args
foo(a="testa", d="excess", c="testc", b="testb", k="another_excess")
As you can see in the above example, we only have parameters a, b, c in the signature of the foo function. Since d and k are not present, they are put into the args dictionary. The output of the program is:
a = testa
b = testb
c = testc
{'k': 'another_excess', 'd': 'excess'}
Example 2:
# Excess positional argument (python 2) example:
def foo(a, b, c, *args):
print "a = %s" % (a,)
print "b = %s" % (b,)
print "c = %s" % (c,)
print args
foo("testa", "testb", "testc", "excess", "another_excess")
Here, since we're testing positional arguments, the excess ones have to be on the end, and *args packs them into a tuple, so the output of this program is:
a = testa
b = testb
c = testc
('excess', 'another_excess')
You can also unpack a dictionary or a tuple into arguments of a function:
def foo(a,b,c,**args):
print "a=%s" % (a,)
print "b=%s" % (b,)
print "c=%s" % (c,)
print "args=%s" % (args,)
argdict = dict(a="testa", b="testb", c="testc", excessarg="string")
foo(**argdict)
Prints:
a=testa
b=testb
c=testc
args={'excessarg': 'string'}
And
def foo(a,b,c,*args):
print "a=%s" % (a,)
print "b=%s" % (b,)
print "c=%s" % (c,)
print "args=%s" % (args,)
argtuple = ("testa","testb","testc","excess")
foo(*argtuple)
Prints:
a=testa
b=testb
c=testc
args=('excess',)
I only have one thing to add that wasn't clear from the other answers (for completeness's sake).
You may also use the stars when calling the function. For example, say you have code like this:
>>> def foo(*args):
... print(args)
...
>>> l = [1,2,3,4,5]
You can pass the list l into foo like so...
>>> foo(*l)
(1, 2, 3, 4, 5)
You can do the same for dictionaries...
>>> def foo(**argd):
... print(argd)
...
>>> d = {'a' : 'b', 'c' : 'd'}
>>> foo(**d)
{'a': 'b', 'c': 'd'}
All of the above answers were perfectly clear and complete, but just for the record I'd like to confirm that the meaning of * and ** in python has absolutely no similarity with the meaning of similar-looking operators in C.
They are called the argument-unpacking and keyword-argument-unpacking operators.
A single star means that the variable 'a' will be a tuple of extra parameters that were supplied to the function. The double star means the variable 'kw' will be a variable-size dictionary of extra parameters that were supplied with keywords.
Although the actual behavior is spec'd out, it still sometimes can be very non-intuitive. Writing some sample functions and calling them with various parameter styles may help you understand what is allowed and what the results are.
def f0(a)
def f1(*a)
def f2(**a)
def f3(*a, **b)
etc...
I find * useful when writing a function that takes another callback function as a parameter:
def some_function(parm1, parm2, callback, *callback_args):
a = 1
b = 2
...
callback(a, b, *callback_args)
...
That way, callers can pass in arbitrary extra parameters that will be passed through to their callback function. The nice thing is that the callback function can use normal function parameters. That is, it doesn't need to use the * syntax at all. Here's an example:
def my_callback_function(a, b, x, y, z):
...
x = 5
y = 6
z = 7
some_function('parm1', 'parm2', my_callback_function, x, y, z)
Of course, closures provide another way of doing the same thing without requiring you to pass x, y, and z through some_function() and into my_callback_function().

Categories