Reputation: 119
I have to use Python 2.7 and I'm running into an issue that I wasn't having in Python 3.
def foo(*dirs, arg2, arg3=None, arg4=None, arg5=False, arg6=False):
I'd call the function like so:
foo('folder_name', arg2=100, arg3=['string', 'string2'], arg4='test6', arg5=True, arg6=False)
But I get an error message saying:
def foo(*dirs, arg2, arg3=None, arg4=None, arg5=False, arg6=False):
^
SyntaxError: invalid syntax
In the definition of the function I can see it says regular parameter after * parameter
. I did some research and can see *dirs
has to be the last parameters specified.
So I can change the function parameters to this:
def foo(arg2, arg3=None, arg4=None, arg5=False, arg6=False, *dirs):
However, when I do this I then get an error message saying:
SyntaxError: non-keyword arg after keyword arg
I'm not sure how to resolve this issue. Does anyone know a way to resolve this? Any help would be much appreciated!
Upvotes: 3
Views: 21105
Reputation: 576
If the dirs
parameter specifies one argument (positional or keyword) for foo
, e.g. one string or one list of strings, in other words IF you intend to call foo
like:
foo("folder_name", other args)
or
foo(["folder_name1", "folder_name2, ...], other args)
then you don't need to prepend its name with *
, and the "workaround" of your answer is actually the way to go. See also: https://docs.python.org/2/tutorial/controlflow.html#more-on-defining-functions .
But if dirs
specifies an arbitrary sequence of arguments and you want to be able to do something like:
foo(other args, "folder_name1", "folder_name2",...)
there is a difference between python 2 and python 3, as you describe in your question. As you can see https://docs.python.org/2/glossary.html#term-parameter versus https://docs.python.org/3/glossary.html#term-parameter , in Python3 there are keyword-only parameters:
Keyword-only parameters can be defined by including a single var-positional parameter or bare * in the parameter list of the function definition before them
That's why in Python3 you didn't have problem defining foo as:
def foo(*dirs, arg2, arg3=None, arg4=None, arg5=False, arg6=False):
and calling it like:
foo('folder_name', arg2=100, arg3=['string', 'string2'], arg4='test6', arg5=True, arg6=False)
Notice, that in the call, you correctly provided all args after "folder_name"
(even arg2
) as keyword arguments, and so worked in Python3.
But in Python2, there are no keyword-only parameters. So, as you mention, you cannot have neither regular parameter after * parameter
nor non-keyword arg after keyword arg
. That's why even if you leave *dirs
last in the parameter list, you cannot call foo
supplying the previous arguments as keyword ones. What you could do, though, is to still leave *dirs
last in the parameter list, and in the call to foo
supply the previous args as positional. Example (python 2.7):
def bar(a=1, b=2, *c): # see below
return (a, b, c)
bar(1, 2, 3) # => (1, 2, (3,))
bar(1, b=3, 3) # => Error: non-keyword arg after keyword arg
bar(1, 2) # => (1 2 ())
bar(1) # => Error: bar() takes at least 2 arguments (1 given)
So, as you can see, even though it lets you define bar with default values for a, b (see positional-or-keyword in links above), they are not used, i.e. a and b are positional (and required).
Lastly, also check these links from python2 documentation: https://docs.python.org/2/tutorial/controlflow.html#unpacking-argument-lists and https://docs.python.org/2/faq/programming.html#what-is-the-difference-between-arguments-and-parameters
Upvotes: 1
Reputation: 119
I found a work around, but am open to other ideas if anyone has any.
I changed *dirs
in the function definition to a keyword argument dirs=None
then when I call foo(dirs='folder_name', other arguments)
works fine.
Upvotes: 1