Arguments vs Parameters in Python — What is the Difference? (Common Questions #1)
Video: Arguments vs Parameters in Python — What is the Difference? (Common Questions #1) by Taught by Celeste AI - AI Coding Coach
Quick answer: parameters are the variables in the function definition. Arguments are the values you pass when calling. Same idea seen from two ends.
It is one of those distinctions that sounds nitpicky until you read your first stack trace. "Got 2 positional arguments but expected 1 parameter." Until you know which is which, you can't read that error.
This is Episode 1 of the Common Questions in Python series — short, focused answers to the questions search engines see most often. Three minutes per video, one concept per episode, working code you can copy.
The definitions
Parameter — a variable that appears in the function's signature. It is the placeholder for whatever value the caller will pass.
Argument — the actual value the caller passes when invoking the function.
def greet(name, greeting="Hello"):
print(f"{greeting}, {name}!")
name and greeting are parameters. They are local variables that exist only inside greet.
greet("Alice")
"Alice" is the argument. It is the actual string that gets bound to the parameter name when the function runs.
The Python docs use the same vocabulary. Error messages use the same vocabulary. Your colleagues will use the same vocabulary. Once you know which is which, every conversation about functions is clearer.
Positional arguments
greet("Alice")
greet("Bob", "Hi")
The most common way to pass arguments. Position determines which parameter each value binds to. "Alice" is in the first position, so it binds to the first parameter (name). "Bob" and "Hi" are in positions one and two, so they bind to name and greeting respectively.
The argument's type doesn't have to match anything explicit — Python is dynamically typed — but the count does. Pass more arguments than the function has parameters, and you get a TypeError: greet() takes 2 positional arguments but 3 were given.
Keyword arguments
greet(greeting="Hey", name="Charlie")
Pass arguments by name instead of by position. The order doesn't matter — greeting is named, so it goes to the greeting parameter regardless of where it appears.
Keyword arguments help readability when:
- The function has many parameters and the order is hard to remember.
- A bool argument's meaning isn't obvious from the call site (
save(force=True)is clearer thansave(True)). - You're skipping early parameters and providing later ones.
You can mix positional and keyword arguments — but keyword arguments must come last:
greet("Charlie", greeting="Hey") # OK: positional then keyword
# greet(greeting="Hey", "Charlie") # SyntaxError: positional after keyword
This is a hard syntax rule. The interpreter doesn't even let your program start if you violate it.
Default values
def greet(name, greeting="Hello"):
print(f"{greeting}, {name}!")
greeting="Hello" makes the parameter optional. If the caller doesn't provide a value, greeting defaults to "Hello". This is why greet("Alice") works even though greet has two parameters — the second one has a default.
A pitfall: don't use mutable values as defaults.
def add_item(item, items=[]): # WRONG
items.append(item)
return items
The list is created once when the function is defined, not each time it's called. Two consecutive calls share the same list. Use None as a sentinel:
def add_item(item, items=None):
if items is None:
items = []
items.append(item)
return items
*args: collecting extra positional arguments
def show_args(*args):
print(f"Got {len(args)} args: {args}")
show_args(1, 2, 3)
# Got 3 args: (1, 2, 3)
The *args parameter collects all extra positional arguments into a tuple. The name args is conventional but not magic — *things works the same way. The asterisk is what does the collecting.
Use *args when the function should accept a variable number of values:
print(*values)works becauseprintuses*args(or its equivalent in C).max(1, 2, 3)andmax(numbers)both work becausemaxuses*args.
**kwargs: collecting extra keyword arguments
def show_kwargs(**kwargs):
print(f"Got kwargs: {kwargs}")
show_kwargs(name="Eve", age=30)
# Got kwargs: {'name': 'Eve', 'age': 30}
The **kwargs parameter collects extra keyword arguments into a dict. Two asterisks for keyword arguments; one for positional.
Use **kwargs when the function should accept a variable number of named values — typically when forwarding to another function:
def my_request(method, url, **kwargs):
print(f"{method} {url} with {kwargs}")
requests.request(method, url, **kwargs) # forward everything else
The combination of *args and **kwargs lets you write functions that pass arbitrary arguments through to another function. It is the signature of every "wrapper" or "decorator" in Python.
The full vocabulary
Putting it all together:
def fn(positional, keyword="default", *args, **kwargs):
pass
fn(1) # positional only
fn(1, "x") # positional + named-but-positional
fn(1, keyword="x") # positional + keyword
fn(1, "x", 2, 3) # extras go into args
fn(1, foo="bar", baz="qux") # extras go into kwargs
fn(1, "x", 2, 3, foo="bar") # mix everything
Five parameter kinds: positional, default, args, keyword-only (with a * before them), *kwargs. Five argument forms: positional, keyword, unpacked-positional (*list), unpacked-keyword (**dict), and combinations.
For most code you write, the simple positional + keyword + default values cover 95% of cases. args and *kwargs come in when you need flexibility — which is most of the time once you start writing libraries or wrappers.
Common mistakes
Putting positional arguments after keyword ones. fn(name="Alice", "Bob") is a SyntaxError. Keywords must come last.
Using mutable defaults. def fn(x=[]) shares the list across calls. Use None as a sentinel.
Confusing *args with args*. The asterisk goes before the name. *args is a parameter that collects; args* is a syntax error.
Forgetting ** to unpack a dict. fn(my_dict) passes the dict as one positional argument. fn(**my_dict) unpacks it into keyword arguments.
Recap
Parameters are variables in the function definition. Arguments are values passed at call time. Positional arguments bind by order; keyword arguments bind by name. Defaults make parameters optional. *args collects extra positionals into a tuple; **kwargs collects extra keywords into a dict. Keyword arguments come after positional ones.
Now when Python yells at you about "expected 2 arguments, got 3" or "unexpected keyword argument," the message reads as a sentence instead of as runes.
Next episode: what are functions? A back-to-basics look at why functions exist, when to write them, and how def actually works.