SyntaxError: non-default argument follows default argument

avatar
Borislav Hadzhiev

Last updated: Apr 8, 2024
5 min

banner

# SyntaxError: non-default argument follows default argument

The Python "SyntaxError: non-default argument follows default argument" occurs when you define a function with a positional parameter that follows a default parameter.

To solve the error, make sure to specify all default parameters after the positional parameters of the function.

syntaxerror non default argument follows default argument

Here is an example of how the error occurs.

main.py
# ⛔️ SyntaxError: non-default argument follows default argument def get_employee(first, last='Doe', salary): return {'first': first, 'last': last, 'salary': salary}

The salary positional parameter follows the last default parameter which causes the error.

# Specify default parameters after the positional ones

To solve the error, make sure to specify the default parameters of the function after the positional ones.

main.py
def get_employee(first, salary, last='Doe'): return {'first': first, 'last': last, 'salary': salary} emp_1 = get_employee('James', 100) print(emp_1) # {'first': 'James', 'last': 'Doe', 'salary': 100} emp_2 = get_employee('Alice', 100, 'Smith') print(emp_2) # {'first': 'Alice', 'last': 'Smith', 'salary': 100}

specify default parameters after positional ones

We moved the last default parameter after the salary positional one which solved the error.

main.py
# ⛔️ Incorrect syntax def get_employee(first, last='Doe', salary): # ✅ Correct syntax (default parameter after positional) def get_employee(first, salary, last='Doe'):

Default parameter values have the form of parameter = expression.

When we declare a function with one or more default parameter values, the corresponding arguments can be omitted when the function is invoked.

main.py
def example(first, last='Doe'): return first + ' ' + last print(example('James')) # 👉️ James Doe print(example('James', 'Smith')) # 👉️ James Smith

If a value for the default parameter is not provided, the default value is used.

In other words, positional parameters are required whereas default parameters are optional.

Positional parameters cannot follow a parameter with a default value.

Otherwise, Python has no way of knowing if we passed an argument for the default parameter or for a positional one.

Here is an example that uses multiple default parameters.

main.py
def example(first, last='Doe', salary=100): return {'first': first, 'last': last, 'salary': salary} # 👇️ {'first': 'James', 'last': 'Doe', 'salary': 100} print(example('James')) # 👇️ {'first': 'James', 'last': 'Smith', 'salary': 100} print(example('James', 'Smith')) # 👇️ {'first': 'James', 'last': 'Smith', 'salary': 50} print(example('James', 'Smith', 50))

The function can be called with one, two or three arguments.

If you want to use the default value for the last parameter but need to specify a default value for salary, use a None value when calling the function.

main.py
def example(first, last='Doe', salary=100): return {'first': first, 'last': last, 'salary': salary} # 👇️ {'first': 'James', 'last': None, 'salary': 50} print(example('James', None, 50))

We passed a None value for the last default parameter, so the default value is used.

# The order of a Python function's parameters

A function's parameters must be defined in the following order:

  1. Positional parameters (required, non-default).
  2. Default parameters or keyword arguments.
  3. *args - receives excess positional arguments.
  4. **kwargs - receives excess keyword arguments.

# Using *args and **kwargs instead

You can specify parameters in the form *identifier or **identifier after default parameters in the function's definition.

main.py
def get_employee(first, salary, last='Doe', *args, **kwargs): print(args) # 👉️ ('developer', ) print(kwargs) # 👉️ {'country': 'Austria'} return {'first': first, 'last': last, 'salary': salary} emp_1 = get_employee('James', 100, 'Smith', 'developer', country='Austria') print(emp_1) # 👉️ {'first': 'James', 'last': 'Doe', 'salary': 100}

using args and kwargs instead

The form *identifier is initialized to a tuple that receives any excess positional arguments.

The form **identifier is initialized to an ordered mapping that receives any excess keyword arguments.

However, note that you might get a confusing result if you omit the value for the last default parameter.

main.py
def get_employee(first, salary, last='Doe', *args, **kwargs): print(args) # 👉️ () print(kwargs) # 👉️ {'country': 'Austria'} return {'first': first, 'last': last, 'salary': salary} emp_1 = get_employee('James', 100, 'developer', country='Austria') print(emp_1) # 👉️ {'first': 'James', 'last': 'developer', 'salary': 100}

Notice that the last parameter got set to a value of developer.

The best way to deal with this is to use a keyword argument for the developer value when calling the function.

main.py
def get_employee(first, salary, last='Doe', *args, **kwargs): print(args) # 👉️ () print(kwargs) # 👉️ {'department': 'developer', 'country': 'Austria'} return {'first': first, 'last': last, 'salary': salary} emp_1 = get_employee('James', 100, department='developer', country='Austria') print(emp_1) # 👉️ {'first': 'James', 'last': 'Doe', 'salary': 100}
It's always better to use keyword arguments for functions that take multiple arguments, where the order is not clear by the function's name.

Keyword arguments use the format of name='value'.

# Only using the **kwargs parameter in the function's definition.

You can also use only **kwargs in the function's definition.

main.py
def get_employee(first, salary, last='Doe', **kwargs): print(kwargs) # 👉️ {'country': 'Austria'} return {'first': first, 'last': last, 'salary': salary} emp_1 = get_employee('James', 100, 'Smith', country='Austria') # 👇️ {'first': 'James', 'last': 'Doe', 'salary': 100} print(emp_1)

The form **identifier is initialized to an ordered mapping that receives any excess keyword arguments.

The country argument in the example is an excess keyword argument and gets added to the **kwargs dictionary.

Keyword arguments use the format of name='value'.

You can pass as many keyword arguments as necessary when using **kwargs.

main.py
def get_employee(first, salary, last='Doe', **kwargs): # 👇️ {'country': 'Austria', 'city': 'Example'} print(kwargs) return {'first': first, 'last': last, 'salary': salary} emp_1 = get_employee('James', 100, country='Austria', city='Example') # 👇️ {'first': 'James', 'last': 'Doe', 'salary': 100} print(emp_1)

We passed country and city keyword arguments to the function and they both got added to the kwargs dictionary.

# Don't set default values for non-primitive parameters

An important note is to avoid setting default values for non-primitive parameters, e.g. dictionaries and lists.

Here is an example of how this can go wrong.

main.py
def get_address(address={}): return address addr1 = get_address() addr2 = get_address() addr1['country'] = 'Germany' print(addr1) # 👉️ {'country': 'Germany'} print(addr2) # 👉️ {'country': 'Germany'}

We called the get_address() function 2 times and stored the results in variables.

Notice that we only set the country key on one of the dictionaries but both of them got updated.

This is because default parameter values are only evaluated once - when the function is defined.

They are not evaluated each time the function is called.

When a non-primitive default parameter value, such as a dictionary or a list, is mutated, it is mutated for all function calls.

One way to get around this issue is to set the default parameter value to None and conditionally update it in the body of the function.

main.py
def get_address(address=None): if address is None: address = {} return address addr1 = get_address() addr2 = get_address() addr1['country'] = 'Germany' print(addr1) # 👉️ {'country': 'Germany'} print(addr2) # 👉️ {}

The body of the function is run every time it is invoked, so the issue no longer exists.

# Additional Resources

You can learn more about the related topics by checking out the following tutorials:

I wrote a book in which I share everything I know about how to become a better, more efficient programmer.
book cover
You can use the search field on my Home Page to filter through all of my articles.