Parameters and Arguments in Python
Terminology
- Parameter: Variable in the function definition
- Argument: Value passed at call time
def greet(name): # 'name' is PARAMETER
print(f"Hello, {name}!")
greet("Ana") # "Ana" is ARGUMENT
Positional Arguments
Match parameters in the order given:
def introduce(name, age, city):
print(f"{name}, {age} years old, from {city}")
# Order matters!
introduce("Ana", 20, "NYC") # Ana, 20 years old, from NYC
introduce(20, "Ana", "NYC") # 20, Ana years old, from NYC (wrong!)
Keyword Arguments (named)
Explicitly specify the parameter name:
def introduce(name, age, city):
print(f"{name}, {age} years old, from {city}")
# Order doesn't matter
introduce(age=20, city="NYC", name="Ana") # Ana, 20 years old, from NYC
# Combination - positional BEFORE keyword
introduce("Ana", city="NYC", age=20) # Ana, 20 years old, from NYC
Default Values
Parameters can have preset values:
def greet(name, greeting="Hello"):
print(f"{greeting}, {name}!")
greet("Ana") # Hello, Ana!
greet("Ana", "Good day") # Good day, Ana!
greet("Ana", greeting="Ciao") # Ciao, Ana!
Parameter order:
Parameters with default values must be after those without:
# CORRECT
def func(required, optional="default"):
pass
# WRONG - SyntaxError
def func(optional="default", required):
pass
WARNING - Mutable values as default:
# WRONG - classic bug!
def add(element, lst=[]):
lst.append(element)
return lst
print(add(1)) # [1]
print(add(2)) # [1, 2] - Not [2]!
print(add(3)) # [1, 2, 3]
# CORRECT
def add(element, lst=None):
if lst is None:
lst = []
lst.append(element)
return lst
*args - Variable Positional Arguments
*args collects extra positional arguments into a tuple:
def total(*numbers):
print(type(numbers)) # <class 'tuple'>
result = 0
for n in numbers:
result += n
return result
print(total(1, 2, 3)) # 6
print(total(1, 2, 3, 4, 5)) # 15
print(total()) # 0
Combining with normal parameters:
def introduce(title, *names):
print(f"{title}:")
for n in names:
print(f" - {n}")
introduce("Students", "Ana", "Bob", "Chris")
# Students:
# - Ana
# - Bob
# - Chris
**kwargs - Variable Keyword Arguments
**kwargs collects extra keyword arguments into a dictionary:
def info(**data):
print(type(data)) # <class 'dict'>
for key, value in data.items():
print(f"{key}: {value}")
info(name="Ana", age=20, city="NYC")
# name: Ana
# age: 20
# city: NYC
Combining with other parameters:
def profile(name, **details):
print(f"Name: {name}")
for k, v in details.items():
print(f" {k}: {v}")
profile("Ana", age=20, job="student")
# Name: Ana
# age: 20
# job: student
Parameter Order
When combining all types, the order is:
- Required positional parameters
*args- Keyword-only parameters (after
*) **kwargs
def func(a, b, *args, c=10, **kwargs):
print(f"a={a}, b={b}")
print(f"args={args}")
print(f"c={c}")
print(f"kwargs={kwargs}")
func(1, 2, 3, 4, c=20, x=30, y=40)
# a=1, b=2
# args=(3, 4)
# c=20
# kwargs={'x': 30, 'y': 40}
Unpacking Arguments
Unpacking list with *:
def total(a, b, c):
return a + b + c
numbers = [1, 2, 3]
print(total(*numbers)) # 6 (equivalent to total(1, 2, 3))
Unpacking dictionary with **:
def introduce(name, age, city):
print(f"{name}, {age}, {city}")
data = {"name": "Ana", "age": 20, "city": "NYC"}
introduce(**data) # Ana, 20, NYC
Keyword-Only Parameters
Parameters after * can only be passed as keyword:
def func(a, b, *, c, d):
print(a, b, c, d)
# Correct
func(1, 2, c=3, d=4)
# Wrong
# func(1, 2, 3, 4) # TypeError
Positional-Only Parameters (Python 3.8+)
Parameters before / can only be passed positionally:
def func(a, b, /, c, d):
print(a, b, c, d)
# Correct
func(1, 2, 3, 4)
func(1, 2, c=3, d=4)
# Wrong
# func(a=1, b=2, c=3, d=4) # TypeError
Common Patterns
Function with multiple options:
def connect(host, port=3306, **options):
print(f"Connecting to {host}:{port}")
for opt, val in options.items():
print(f" {opt}={val}")
connect("localhost")
connect("db.server.com", 5432, user="admin", ssl=True)
Generic wrapper:
def log_call(function):
def wrapper(*args, **kwargs):
print(f"Call: {function.__name__}")
return function(*args, **kwargs)
return wrapper
Common Mistakes
1. Wrong order when calling
def f(a, b):
pass
# f(a=1, 2) # SyntaxError - keyword before positional!
f(1, b=2) # Correct
2. Mutable value as default
# WRONG
def f(lst=[]):
lst.append(1)
return lst
# CORRECT
def f(lst=None):
if lst is None:
lst = []
lst.append(1)
return lst
3. Confusion *args and **kwargs
def f(*args, **kwargs):
print(args) # tuple
print(kwargs) # dict
f(1, 2, a=3, b=4)
# (1, 2)
# {'a': 3, 'b': 4}
Key Points for Exam
- Positional parameters: order matters
- Keyword parameters: order doesn’t matter
- Default values: required parameters first
*args: tuple with extra positional arguments**kwargs: dict with extra keyword arguments- NEVER use list/dict as mutable default value!
- Unpacking:
*list,**dictionary
Review Questions
- What’s the difference between parameter and argument?
- What data type is
*args? And**kwargs? - Why don’t we use
lst=[]as default? - In what order do we place parameters?