Learn Python: The Fundamentals

Understanding how to pass information into functions is key to writing flexible, reusable code. In this lesson, you’ll learn the difference between parameters (names in a function definition) and arguments (actual values you pass when calling the function), plus how to use positional, keyword, and default values — and a quick intro to *args, **kwargs, and unpacking.

 

Parameters vs Arguments

A parameter is the variable in the function definition. An argument is the value you supply when calling the function.

 

def greet(name):   # 'name' is a parameter
    print(f"Hello, {name}!")

greet("Tyler")      # "Tyler" is an argument

 

Positional Arguments

Arguments matched by position are the most common — the first argument goes to the first parameter, and so on.

 

def report_city(name, city):
    print(f"{name} lives in {city}.")

report_city("Maya", "Sydney")    # positional match

 

Keyword Arguments

Keyword arguments match by name=value, letting you pass values in any order and making calls self-documenting.

 

def make_account(username, role):
    print(f"User: {username}, Role: {role}")

make_account(role="student", username="tyler")  # order swapped, still works

 

Default Parameter Values

Give parameters default values so callers can omit them. Defaults are evaluated once (see pitfall below).

 

def shout(msg, times=1, upper=True):
    if upper:
        msg = msg.upper()
    for i in range(times):
        print(msg)

shout("nice work")                  # uses defaults
shout("ok", 2, False)              # positional
shout(msg="custom", upper=False) # keywords

 

Mixing Positional and Keyword

You can mix them — but positional arguments must come first.

 

def connect(host, port, secure=True):
    print(f"host={host}, port={port}, secure={secure}")

connect("example.com", 443, secure=True)  # OK
# connect(host="example.com", 443)   ← Error: positional after keyword

 

Unpacking with * and **

Use * to unpack a sequence into positional arguments, and ** to unpack a dict into keyword arguments.

 

def area(w, h):
    return w * h

dims = (3, 5)
print(area(*dims))     # 15

opts = {"w": 4, "h": 7}
print(area(**opts))     # 28

 

Variable-length Parameters: *args and **kwargs

Capture “any number” of positional or keyword arguments in your function.

 

def summarize(*args, **kwargs):
    print("Positional:", args)
    print("Keywords:", kwargs)

summarize(1, 2, 3, mode="fast", retry=2)

 

Common Pitfall: Mutable Defaults

Never use a mutable object (like a list or dict) as a default parameter. It persists across calls.

 

# Bad: shared list used across calls
def append_item(item, bucket=[]):
    bucket.append(item)
    return bucket

print(append_item("a"))  # ['a']
print(append_item("b"))  # ['a','b'] ← unexpected carry-over

Fix it by using None and creating a new object inside the function.

 

def append_item(item, bucket=None):
    if bucket is None:
        bucket = []
    bucket.append(item)
    return bucket

print(append_item("a"))  # ['a']
print(append_item("b"))  # ['b']

 

Interactive Exercise: Parameters & Arguments Playground

Experiment with positional args, keyword args, defaults, and unpacking. Then try adding *args / **kwargs support.

 

# 1) Define a function with defaults
def format_name(first, last, middle="", title=""):
parts = [title, first, middle, last]
return " ".join([p for p in parts if p])

print(format_name("Tyler", "Connor")) # positional
print(format_name(first="Maya", last="Lee", title="Dr.")) # keywords

# 2) Mix positional + keyword (positional first)
print(format_name("Alex", "Kim", title="Mr"))

# 3) Unpack a tuple and dict into a call
t = ("Ada", "Lovelace")
print(format_name(*t))

d = {"first": "Grace", "last": "Hopper", "title": "Rear Adm."}
print(format_name(**d))

# 4) Your turn:
# - Add *args to collect extra name parts and include them in the output.
# - Add **kwargs to accept optional fields like 'suffix' and append them.

Remember: positional args first, then keyword args. Use * and ** to unpack.
Avoid mutable defaults. Prefer None and create the list/dict inside the function.

Mastering parameters and arguments lets you design clear, flexible APIs for your functions — and makes your code far easier to read, test, and reuse.