DEV Community

Cover image for Python Functions & Arguments: From Basics to *args and **kwargs
Suchismita Moharana
Suchismita Moharana

Posted on

Python Functions & Arguments: From Basics to *args and **kwargs

If you are learning Python, functions feel easy at first. You define them, pass arguments, get results. Then one day you encounter *args and **kwargs, and suddenly function calls look confusing and unpredictable.

This article is designed as one complete learning source. We will start from absolute basics and slowly move toward advanced, production‑ready patterns used in real Python libraries.

By the end of this post, a beginner will understand not just what *args and **kwargs are, but why they exist and how professionals design APIs using them.

We will build everything step by step using one evolving example: create_subway() 🥪


1. What Is a Function?

A function is a reusable block of code that:

  • accepts input (arguments)
  • performs logic
  • optionally returns output
def greet(name):
    return f"Hello {name}"

greet("Jazz")
Enter fullscreen mode Exit fullscreen mode

Here:

  • nameparameter (defined in function)
  • "Jazz"argument (passed during call)

This distinction matters once arguments become flexible.


2. Positional Arguments (Order Matters)

def create_subway(size, bread):
    print(size, bread)

create_subway(30, "multi-grain")
Enter fullscreen mode Exit fullscreen mode

Python assigns values by position:

  • 30size
  • "multi-grain"bread

If you swap them, Python won’t complain — but your logic will break.


3. Keyword Arguments (Name Matters)

create_subway(bread="multi-grain", size=30)
Enter fullscreen mode Exit fullscreen mode

Now:

  • Order doesn’t matter
  • Names do

Critical Rule (Very Important)

Python always assigns positional arguments first, from left to right, before it processes keyword arguments.

This single rule explains most *args / **kwargs confusion.


4. Why Fixed Arguments Don’t Scale

Imagine a real sandwich order:

  • size
  • bread
  • quantity
  • veges
  • sauces
  • extras

You cannot keep adding parameters forever:

def create_subway(size, bread, veges, sauce, extras, cheese_type, toast_level):
    ...
Enter fullscreen mode Exit fullscreen mode

This becomes unreadable and fragile.

Python solves this with variable arguments.


5. *args — Variable Positional Arguments

*args collects extra positional arguments into a tuple.

Beginner Version

def create_subway(size, bread, *args):
    print(f"Size: {size}")
    print(f"Bread: {bread}")
    print(f"Extras: {args}")
Enter fullscreen mode Exit fullscreen mode

Call:

create_subway(30, "multi-grain", "cheese", "paneer", "jalapeno")
Enter fullscreen mode Exit fullscreen mode

Internally:

args == ("cheese", "paneer", "jalapeno")
Enter fullscreen mode Exit fullscreen mode

When to Use *args

  • Number of values is unknown
  • Order matters
  • Names don’t matter

6. **kwargs — Variable Keyword Arguments

**kwargs collects extra keyword arguments into a dictionary.

Example

def create_subway(size, bread, **kwargs):
    print(f"Size: {size}")
    print(f"Bread: {bread}")
    print("Options:", kwargs)
Enter fullscreen mode Exit fullscreen mode

Call:

create_subway(
    30,
    "multi-grain",
    veges=["olive", "cucumber"],
    sauce=["bbq", "honey-mustard"]
)
Enter fullscreen mode Exit fullscreen mode

Internally:

kwargs == {
    "veges": [...],
    "sauce": [...]
}
Enter fullscreen mode Exit fullscreen mode

When to Use **kwargs

  • Optional configuration
  • Named values
  • Future‑proof APIs

7. Using *args and **kwargs Together

Correct order must be followed:

def create_subway(size, bread="multi-grain", *args, **kwargs):
    ...
Enter fullscreen mode Exit fullscreen mode

Order rule:

  1. Required parameters
  2. Default parameters
  3. *args
  4. **kwargs

8. Why bread Became Positional (Common Confusion)

create_subway(30, 2, bread="honey-bread")
Enter fullscreen mode Exit fullscreen mode

Step-by-step binding

Position Parameter Value
1 size 30
2 bread 2

Python assigns positional arguments first.

Now bread already has a value (2).

When Python sees:

bread="honey-bread"
Enter fullscreen mode Exit fullscreen mode

It raises:

TypeError: got multiple values for argument 'bread'
Enter fullscreen mode Exit fullscreen mode

Nothing is converted. Position alone decides binding.


9. Defensive create_subway()

Beginner‑safe version:

def create_subway(size, bread="multi-grain", *args, **kwargs):
    print(f"Size: {size}")
    print(f"Bread: {bread}")

    if args:
        print(f"Quantity: {args[0]}")

    veges = kwargs.get("veges", [])
    sauces = kwargs.get("sauce", [])

    print("Veges:", veges)
    print("Sauces:", sauces)
Enter fullscreen mode Exit fullscreen mode

10. Production‑Ready Version (Recommended)

def create_subway(
    size: int,
    bread: str = "multi-grain",
    quantity: int = 1,
    *,
    veges=None,
    sauces=None
):
    veges = veges or []
    sauces = sauces or []

    print("Order Summary")
    print("-" * 20)
    print(f"Size     : {size}")
    print(f"Bread    : {bread}")
    print(f"Quantity : {quantity}")
    print(f"Veges    : {veges}")
    print(f"Sauces   : {sauces}")
Enter fullscreen mode Exit fullscreen mode

Call:

create_subway(
    30,
    bread="honey-bread",
    quantity=2,
    veges=["olive", "cucumber"],
    sauces=["bbq"]
)
Enter fullscreen mode Exit fullscreen mode

Why This Is Production‑Ready

  • Keyword‑only arguments (*)
  • Type hints
  • Explicit API
  • No hidden positional traps

11. Real‑World Usage from Popular Libraries

print()

print("Jazz", "Suchi", sep=", ", end="!")
Enter fullscreen mode Exit fullscreen mode

Internally uses:

def print(*args, **kwargs):
    ...
Enter fullscreen mode Exit fullscreen mode

logging

logger.info("User %s logged in", user_id, extra={"ip": ip})
Enter fullscreen mode Exit fullscreen mode
  • *args → message formatting
  • **kwargs → metadata

requests

requests.get(
    url,
    headers={...},
    timeout=5,
    params={...}
)
Enter fullscreen mode Exit fullscreen mode

Flexible APIs powered by **kwargs.


pandas

df.drop(columns=["A"], inplace=True, errors="ignore")
Enter fullscreen mode Exit fullscreen mode

Keyword arguments allow backward compatibility and clean defaults.


12. Mental Model That Sticks

  • *args → extra values
  • **kwargs → extra named settings
  • Positional arguments lock slots first
  • Keywords cannot override positions

Final Takeaway

If you understand:

  • how Python binds arguments
  • why position beats name
  • when to use *args vs **kwargs

You are no longer a beginner.

You are designing flexible, professional Python APIs — exactly how real libraries do it.

Happy coding 🚀

Top comments (0)