Blog Post #103: The Full Function Signature: Ordering All Argument Types

In our journey through functions, we’ve encountered several types of parameters: standard positional parameters, parameters with default values (Post #89), the catch-all *args (Post #101), and the catch-all **kwargs (Post #102).

A natural question arises: “Can we use all of these in a single function?” The answer is yes! But Python is very strict about this. To avoid ambiguity, you must define them in a specific, non-negotiable order. In this post, we will learn the definitive order for all parameter types in a Python function signature.

The Golden Rule of Parameter Order

When you define a function that uses a combination of different parameter types, they must appear in the following sequence:

  1. Standard Positional Parameters (e.g., a, b)
  2. Parameters with Default Values (e.g., c=None, d=True)
  3. The *args Parameter (the catch-all for extra positional arguments)
  4. The **kwargs Parameter (the catch-all for extra keyword arguments)

You don’t have to use all of them, but any that you do use must follow this order.

The “Kitchen Sink” Example

Let’s create a function that uses all four types in the correct order. We’ll call it the “kitchen sink” function because it includes a bit of everything!

def kitchen_sink_function(pos1, pos2, default1="hello", default2=None, *args, **kwargs):
    """A function that demonstrates the full parameter order."""
    print("--- Function Call Results ---")
    print(f"Standard Positional: pos1='{pos1}', pos2='{pos2}'")
    print(f"Default Values: default1='{default1}', default2={default2}")
    print(f"args (Tuple): {args}")
    print(f"kwargs (Dictionary): {kwargs}")

This function signature tells Python: “Expect at least two positional arguments (pos1, pos2). The next two (default1, default2) have default values and are optional. Any other positional arguments should be collected into the args tuple. Any keyword arguments that don’t match the named parameters should be collected into the kwargs dictionary.”

Calling a Complex Function

Let’s see how Python distributes the arguments when we call this function in a few different ways.

Call 1: Only Required Arguments

Here, we only provide the two required positional arguments.

kitchen_sink_function('val1', 'val2')

Output:

--- Function Call Results ---
Standard Positional: pos1='val1', pos2='val2'
Default Values: default1='hello', default2=None
args (Tuple): ()
kwargs (Dictionary): {}

Call 2: Providing Extra Positional Arguments

Here, we provide enough arguments to fill the standard parameters, override the defaults, and have some left over for *args.

kitchen_sink_function(1, 2, 3, 4, 5, 6)

Python maps them in order:

  • 1 -> pos1
  • 2 -> pos2
  • 3 -> default1
  • 4 -> default2
  • (5, 6) -> collected into args

Output:

--- Function Call Results ---
Standard Positional: pos1='1', pos2='2'
Default Values: default1='3', default2=4
args (Tuple): (5, 6)
kwargs (Dictionary): {}

Call 3: The Full Monty

Now let’s provide arguments for everything.

kitchen_sink_function(1, 2, 3, 4, 5, 6, setting1='ON', setting2='OFF')

Python distributes them just as before, but this time the extra keyword arguments are collected into **kwargs.

Output:

--- Function Call Results ---
Standard Positional: pos1='1', pos2='2'
Default Values: default1='3', default2=4
args (Tuple): (5, 6)
kwargs (Dictionary): {'setting1': 'ON', 'setting2': 'OFF'}

Incorrect Order Leads to an Error

This order is not just a convention; it’s a strict syntax rule. If you try to define a function with the parameters out of order, Python will raise a SyntaxError before your code even runs.

# This will cause a SyntaxError!
# def invalid_function(pos1, default1="hello", *args, pos2):
#     pass

You cannot have a regular parameter (pos2) after the catch-all *args.

What’s Next?

You now know the correct order for defining a function’s parameters: standard, then default, then *args, then **kwargs. While you’ll rarely write a function that uses all of them at once, understanding this hierarchy is essential for reading and writing complex functions in Python.

We’ve spent a lot of time learning the mechanics of defining and calling functions. Now, we’re going to step back and look at a profound and powerful concept in Python: what a function is. In Python, functions aren’t just blocks of code; they are objects, just like numbers and strings. In Post #104, we will explore what it means for functions to be first-class citizens.

Author

Debjeet Bhowmik

Experienced Cloud & DevOps Engineer with hands-on experience in AWS, GCP, Terraform, Ansible, ELK, Docker, Git, GitLab, Python, PowerShell, Shell, and theoretical knowledge on Azure, Kubernetes & Jenkins. In my free time, I write blogs on ckdbtech.com

Leave a Comment