SyntaxError: positional argument follows keyword argument

avatar
Borislav Hadzhiev

Last updated: Apr 8, 2024
5 min

banner

# SyntaxError: positional argument follows keyword argument

The Python "SyntaxError: positional argument follows keyword argument" occurs when we pass keyword arguments before positional ones in a call to a function.

To solve the error, pass positional arguments in the right order and pass any keyword arguments after the positional ones.

syntaxerror positional argument follows keyword argument

Here is an example of how the error occurs.

main.py
def get_employee(first, last, salary): return {'first': first, 'last': last, 'salary': salary} # ⛔️ SyntaxError: positional argument follows keyword argument get_employee('Bobby', last='Hadz', 100)

positional argument after keyword argument

Passing a positional argument to a function looks like 'Bobby',, whereas passing a keyword argument to a function looks like last='Hadz'.

  • when passing a positional argument to a function, only the value is passed, e.g. 'Bobby'.
  • when passing a keyword argument to a function, the name of the argument and the corresponding value are passed, e.g. first = 'Bobby'.
The error was caused because we passed a keyword argument last, and then provided a value for the salary positional argument.

If you specify keyword arguments before positional ones, Python has no way of knowing a value for which positional argument is provided.

Instead, the keyword arguments must come after the positional ones.

main.py
def get_employee(first, last, salary): return {'first': first, 'last': last, 'salary': salary} # ✅ Keyword arguments come after positional ones result = get_employee('Bobby', last='Hadz', salary=100) # 👇️ {'first': 'Bobby', 'last': 'Hadz', 'salary': 100} print(result)

keyword arguments must come after positional ones

We passed first as a positional argument and last and salary as keyword arguments to resolve the issue.

# Only passing positional arguments to the function

One way to solve the error is to only pass positional arguments to the function.

main.py
def get_employee(first, last, salary): return {'first': first, 'last': last, 'salary': salary} # ✅ Only passing positional arguments to the function result = get_employee('Bobby', 'Hadz', 100) print(result) # 👉️ {'first': 'Bobby', 'last': 'Hadz', 'salary': 100}

only passing positional arguments

The example above only uses positional arguments. The function knows for which parameter we passed a value based on the order of the positional arguments.

# Only passing keyword arguments to the function

Alternatively, you can only pass keyword arguments to the function.

main.py
def get_employee(first, last, salary): return {'first': first, 'last': last, 'salary': salary} result = get_employee(salary=100, first='Alice', last='Smith') print(result) # 👉️ {'first': 'Bobby', 'last': 'Hadz', 'salary': 100}

keyword arguments only passed to function

We only passed keyword arguments in the function call. Python knows for which parameter we passed a value based on the name of the keyword argument, e.g. salary=100.

# Passing positional and keyword arguments to the function

You can also pass positional and keyword arguments in the same function call. Note that keyword arguments must follow positional ones.

main.py
def get_employee(first, last, salary): return {'first': first, 'last': last, 'salary': salary} result = get_employee('Bobby', salary=100, last='Hadz') print(result) # 👉️ {'first': 'Bobby', 'last': 'Hadz', 'salary': 100}

passing positional and keyword arguments

We used a positional argument (Bobby) and 2 keyword arguments - (salary=100 and last='Hadz').

Make sure that any positional arguments you specify in the function call are passed in the correct order (the order must correspond to the parameter list in the function's definition).

The order you pass the keyword arguments in doesn't matter, as long as they come after the positional ones.

# The order of the positional arguments matters

Make sure that you aren't just blindly moving the keyword arguments after all of the positional ones because the order of the positional arguments matters.

Here is an example of how this can go wrong.

main.py
def get_employee(first, last, salary): return {'first': first, 'last': last, 'salary': salary} # ⛔️ TypeError: get_employee() got multiple values for argument 'last' result = get_employee('Bobby', 100, last='Hadz')

The keyword argument in the example comes after any positional ones, but we still got an error.

The reason we got the error is that we used positional arguments to pass a value for the first and last parameters and then passed a value for the last parameter using a keyword argument.

The easiest way to solve the error in the example is to pass only positional arguments (in the correct order) to the function.

main.py
def get_employee(first, last, salary): return {'first': first, 'last': last, 'salary': salary} # ✅ Only passing positional arguments (in the correct order) result = get_employee('Bobby', 'Hadz', 100) # 👇️ {'first': 'Bobby', 'last': 'Hadz', 'salary': 100} print(result)

# 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 **kwrags in a function's definition

You might also see the *args and **kwargs syntax being used to receive excess positional or keyword arguments in a function.

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

using args and kwargs in function definition

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.

An excess positional argument with the value of developer was supplied to the function, so it got added to the args tuple.

Similarly, the function doesn't define a country argument, so it got added to the **kwargs dictionary.

We passed the value developer as a positional argument and the country='Belgium' value as a keyword argument.

main.py
emp_1 = get_employee( 'Bobby', 100, 'Hadz', 'developer', country='Belgium' )

Note that the keyword argument comes after all positional ones.

You can also only use **kwargs or *args, depending on your use case.

# Only taking excess keyword arguments

Here is an example function that only takes excess keyword arguments.

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

only taking excess keyword arguments

The function doesn't define the country and city arguments, so they got added to the kwargs dictionary.

# Define default parameters after positional ones

The same is the case when a function definition has default parameters - it has to define its default parameters after the positional ones.

main.py
# 👇️ default parameter `last='Doe'` def get_employee(first, salary, last='Doe'): return {'first': first, 'last': last, 'salary': salary} # 👇️ not passing value for default parameter emp_1 = get_employee('Bobby', 100) print(emp_1) # {'first': 'Bobby', 'last': 'Doe', 'salary': 100} # 👇️ passing value for default parameter emp_2 = get_employee('Alice', 100, 'Smith') print(emp_2) # {'first': 'Alice', 'last': 'Smith', 'salary': 100}

define default parameters after positional ones

Default parameter values have the form 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.

Positional parameters cannot follow a parameter with a default value because otherwise, Python has no way of knowing if we passed an argument for the default parameter or for a positional one.

# 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.