DocsHub
Functions

Arguments

Learn the different ways to pass data into functions in Python — positional, keyword, default, *args, and **kwargs.

Arguments

When you call a function, you pass in data for it to work with. Python gives you several different ways to do this — each one useful in different situations. Understanding them well makes your functions flexible, readable, and powerful.


Positional arguments

The simplest kind. Values are matched to parameters by their position — first argument goes to the first parameter, second to the second, and so on.

def introduce(name, age, city):
    print(f"My name is {name}, I am {age}, from {city}.")

introduce("Ali", 22, "Lahore")
# My name is Ali, I am 22, from Lahore.

Order matters. If you swap them, the values go to the wrong parameters:

introduce(22, "Lahore", "Ali")
# My name is 22, I am Lahore, from Ali.

Keyword arguments

Instead of relying on position, you name the parameter explicitly when calling the function:

introduce(name="Ali", age=22, city="Lahore")
# My name is Ali, I am 22, from Lahore.

Because you are naming them, order no longer matters:

introduce(city="Lahore", name="Ali", age=22)
# My name is Ali, I am 22, from Lahore.

You can also mix positional and keyword — but positional arguments must always come first:

introduce("Ali", city="Lahore", age=22)   # fine
introduce(name="Ali", 22, "Lahore")       # SyntaxError — keyword before positional

Keyword arguments make function calls much easier to read, especially when a function has many parameters. create_user("Ali", True, False, 3) tells you nothing — create_user("Ali", is_admin=True, is_banned=False, role=3) tells you everything.


Default arguments

You can give a parameter a default value. If the caller does not pass that argument, the default is used.

def greet(name, message="Hello"):
    print(f"{message}, {name}!")

greet("Ali")                  # Hello, Ali!
greet("Sara", "Good morning") # Good morning, Sara!

Default parameters must always come after non-default ones:

def greet(message="Hello", name):   # SyntaxError
    pass

def greet(name, message="Hello"):   # correct
    pass

A practical example — a function that creates a user profile with sensible defaults:

def create_user(username, role="viewer", is_active=True):
    print(f"User: {username} | Role: {role} | Active: {is_active}")

create_user("ali")
# User: ali | Role: viewer | Active: True

create_user("sara", role="admin")
# User: sara | Role: admin | Active: True

create_user("omar", role="editor", is_active=False)
# User: omar | Role: editor | Active: False

Never use a mutable object like a list or dictionary as a default value. This is a well-known Python trap:

# Wrong — the list is shared across all calls
def add_item(item, cart=[]):
    cart.append(item)
    return cart

print(add_item("apple"))    # ['apple']
print(add_item("banana"))   # ['apple', 'banana'] — not what you expected

Use None as the default and create the object inside the function instead:

# Correct
def add_item(item, cart=None):
    if cart is None:
        cart = []
    cart.append(item)
    return cart

*args — variable positional arguments

What if you want a function to accept any number of positional arguments? Use *args. Python collects all extra positional arguments into a tuple.

def add(*args):
    print(args)
    return sum(args)

print(add(1, 2))           # (1, 2) → 3
print(add(1, 2, 3, 4, 5))  # (1, 2, 3, 4, 5) → 15

The name args is just a convention — the * is what matters. You could write *numbers and it would work the same way.

def greet(*names):
    for name in names:
        print(f"Hello, {name}!")

greet("Ali", "Sara", "Omar")
# Hello, Ali!
# Hello, Sara!
# Hello, Omar!

You can combine regular parameters with *args — but *args must come after regular parameters:

def introduce(greeting, *names):
    for name in names:
        print(f"{greeting}, {name}!")

introduce("Hi", "Ali", "Sara", "Omar")
# Hi, Ali!
# Hi, Sara!
# Hi, Omar!

**kwargs — variable keyword arguments

**kwargs does the same thing but for keyword arguments. Python collects all extra keyword arguments into a dictionary.

def show_info(**kwargs):
    print(kwargs)

show_info(name="Ali", age=22, city="Lahore")
# {'name': 'Ali', 'age': 22, 'city': 'Lahore'}

You can loop over it like any dictionary:

def display_profile(**kwargs):
    for key, value in kwargs.items():
        print(f"{key}: {value}")

display_profile(name="Ali", age=22, city="Lahore", role="admin")

Output:

name: Ali
age: 22
city: Lahore
role: admin

A practical example — a flexible function that builds an HTML tag:

def build_tag(tag, content, **attributes):
    attrs = ""
    for key, value in attributes.items():
        attrs += f' {key}="{value}"'
    return f"<{tag}{attrs}>{content}</{tag}>"

print(build_tag("a", "Click here", href="https://example.com", target="_blank"))
# <a href="https://example.com" target="_blank">Click here</a>

print(build_tag("p", "Hello world", class_="intro", id="main"))
# <p class_="intro" id="main">Hello world</p>

The correct order

When you combine all argument types in one function, they must follow this order:

def function(positional, default=value, *args, **kwargs):
def example(name, role="viewer", *args, **kwargs):
    print(f"name: {name}")
    print(f"role: {role}")
    print(f"args: {args}")
    print(f"kwargs: {kwargs}")

example("Ali", "admin", "extra1", "extra2", city="Lahore", age=22)

Output:

name: Ali
role: admin
args: ('extra1', 'extra2')
kwargs: {'city': 'Lahore', 'age': 22}

Unpacking arguments with * and **

You can also go the other way — unpack a list or dictionary into a function call:

def add(a, b, c):
    return a + b + c

numbers = [1, 2, 3]
print(add(*numbers))   # 6 — unpacks the list into positional args

data = {"a": 1, "b": 2, "c": 3}
print(add(**data))     # 6 — unpacks the dict into keyword args

Summary

TypeSyntaxWhat it does
Positionalfunc(1, 2)Matched by order
Keywordfunc(a=1, b=2)Matched by name
Defaultdef func(a=10)Used when not passed
*argsdef func(*args)Collects extra positional into a tuple
**kwargsdef func(**kwargs)Collects extra keyword into a dict
Unpack listfunc(*list)Spreads list into positional args
Unpack dictfunc(**dict)Spreads dict into keyword args

On this page