14

I am learning to use positional arguments in python and also trying to see how they work when mixed up with default arguments:-

def withPositionalArgs(ae=9,*args):
    print 'ae= ', ae
    print 'args = ', args


a=1
b=2
c=[10,20]

withPositionalArgs(a,b,c)

This gives me the output:

ae=  1
args =  (2, [10, 20])

As you can see, a is considered to be a value passed for ae, and b as well as c are considered to be the positional arguments.

So, I am now trying to assign 10 for ae while calling withPositionalArgs:

withPositionalArgs(ae=10,b,c)

But, I can not do it. I get the error:

SyntaxError: non-keyword arg after keyword arg

My question is:

Am I doing correctly? Is having default argument allowed or a good practice to use before positional arguments in python functions?

2
  • 2
    You could call it with withPositionalArgs(10,b,c). Commented Sep 8, 2012 at 16:03
  • The "surprising" thing is that calling ...(1,ae=2) throws TypeError: ...() got multiple values for keyword argument 'ae'. Commented Sep 8, 2012 at 16:30

3 Answers 3

15

In Python2, you are not allowed to put arguments which have a default value before positional arguments.

The positional arguments must come first, then the arguments with default values (or, when calling the function, the keyword arguments), then *args, and then **kwargs.

This order is required for both the function definition and for function calls.

In Python3, the order has been relaxed. (For example, *args can come before a keyword argument in the function definition.) See PEP3102.

Sign up to request clarification or add additional context in comments.

5 Comments

@unubtu: Is is not allowed both in the definition as well as the function call? Or only at 1 place?
This is the order one must use for both the definition and the function call. Though, in the function call, you can do things like foo(c = 1, ae = 3, b = 2). That is, the order of the arguments can be jumbled by supplying them keyword arguments.
It may seem silly to ask, but, Vaughn Cato's comment to my answer allows me to pass the argumenta as required, and python does not give any error. So, shall I modify your answer like: In Python, In function calls, you are not allowed to put arguments which have a default parameter before positional arguments. But, you are allowed to do so in function definition ?
@GodMan The "default values" part is a red herring.
Commenting for @bal: When calling the function, keyword arguments come after *args and such to avoid the "Positional argument before keyword argument" error.
4

I think we should make the distinction of default values vs. passing in arbitrary arguments/key-value pairs. The behaviour without default values is the same:

def f(ae,*args, **kwargs):
    print 'ae     = ', ae
    print 'args   = ', args
    print 'kwargs = ', kwargs

The way we have written this means that the first argument passed into f in the tuple args, that is f(1,2,3,a=1,b=2) (the sequence goes explicit arguments, *args, **kwargs.) Here: ae = 1, args = (2,3), kwargs = {'a': 1, 'b': 2}.

If we try to pass in f(1,2,3,a=1,ae=3) we are thrown a TypeError: f() got multiple values for keyword argument 'ae', since the value of ae is attempted to be changed twice.

.

One way around this is to only set ae when it is explicitly prescribed, we could (after the def line):

def g(*args, **kwargs):
    kwargs, kwargs_temp = {"ae": 9}, kwargs
    kwargs.update(kwargs_temp) #merge kwargs into default dictionary

and this time g(1,2,3,a=1,ae=3) sets args=(1,2,3), kwargs={a=1,ae=3}.

However, I suspect this is not best practice...

Comments

1

Python3 has relaxed ordering.

Now you can do something like:

def withPositionalArgs(*args, ae=9):
    print('ae=', ae)
    print('args =', args)
a=1
b=2
c=[10, 20]
withPositionalArgs(a, b, c, ae=7)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.