- Positional arguments — arguments passed in order
- Keyword arguments — arguments passed by name
- Default arguments — arguments with default values
- Variable-length arguments — *args and **kwargs
- Positional-only arguments — / syntax
- Keyword-only arguments — * syntax
Introduction to Function Arguments
In Python, arguments are the values you pass to a function when you call it. Python provides a rich and flexible system for passing arguments, allowing you to write functions that are both powerful and easy to use.
💡 Key concept: Arguments are the actual values passed to a function, while parameters are the variables defined in the function. Python offers multiple ways to pass arguments, making functions versatile and user-friendly.
Positional Arguments
Arguments in Order
# Positional arguments are passed in the order they are defined
# The order matters!
# 1. Basic positional arguments
def greet(name, greeting):
"""Greet a person with a custom greeting"""
return f"{greeting}, {name}!"
# Order matters
print(greet("Alice", "Hello")) # Hello, Alice!
print(greet("Bob", "Hi")) # Hi, Bob!
# 2. Multiple positional arguments
def calculate_total(price, quantity, tax_rate):
"""Calculate total cost with tax"""
subtotal = price * quantity
tax = subtotal * tax_rate
return subtotal + tax
# Position matters
print(calculate_total(10, 3, 0.10)) # 33.0 (10*3 + 10*3*0.10)
print(calculate_total(3, 10, 0.10)) # 33.0 (3*10 + 3*10*0.10)
# 3. Different types of positional arguments
def process_user(name, age, is_active, score):
"""Process user data"""
return {
"name": name,
"age": age,
"active": is_active,
"score": score
}
user = process_user("Alice", 25, True, 95.5)
print(user) # {'name': 'Alice', 'age': 25, 'active': True, 'score': 95.5}
# 4. Positional arguments with type hints
def calculate_area(length: float, width: float) -> float:
"""Calculate area of a rectangle"""
return length * width
print(calculate_area(5.5, 3.2)) # 17.6
# 5. Common mistake - wrong order
def create_user(username, email, age):
return f"User: {username}, Email: {email}, Age: {age}"
# Wrong order
print(create_user("alice@email.com", "alice123", 25))
# User: alice@email.com, Email: alice123, Age: 25
# Correct order
print(create_user("alice123", "alice@email.com", 25))
# User: alice123, Email: alice@email.com, Age: 25
Positional arguments key points:
- Order matters — arguments must be passed in the correct order
- Required — all positional arguments must be provided
- Common use — when the meaning of each argument is obvious
- Potential errors — passing arguments in the wrong order
Quick Check: Do positional arguments need to be passed in order? (Answer: Yes, the order matters)
Keyword Arguments
Arguments by Name
# Keyword arguments are passed using the parameter name
# Order doesn't matter!
# 1. Basic keyword arguments
def greet(name, greeting):
return f"{greeting}, {name}!"
# Order doesn't matter with keyword arguments
print(greet(greeting="Hello", name="Alice")) # Hello, Alice!
print(greet(name="Bob", greeting="Hi")) # Hi, Bob!
# 2. Mixing positional and keyword arguments
def create_profile(name, age, city, occupation):
return f"{name} ({age}) from {city} - {occupation}"
# Positional first, then keyword
print(create_profile("Alice", 25, occupation="Engineer", city="NYC"))
# Alice (25) from NYC - Engineer
# 3. Keyword arguments with default values
def greet_user(name, greeting="Hello", punctuation="!"):
return f"{greeting}, {name}{punctuation}"
print(greet_user("Alice")) # Hello, Alice!
print(greet_user("Bob", punctuation="?")) # Hello, Bob?
print(greet_user(greeting="Hi", name="Charlie")) # Hi, Charlie!
# 4. Benefits of keyword arguments
# More readable code
def create_user(first_name, last_name, age, email, phone, is_active=True):
return {
"first": first_name,
"last": last_name,
"age": age,
"email": email,
"phone": phone,
"active": is_active
}
# Positional - hard to remember order
user1 = create_user("John", "Doe", 30, "john@email.com", "555-1234", True)
# Keyword - clear and self-documenting
user2 = create_user(
first_name="Jane",
last_name="Smith",
age=28,
email="jane@email.com",
phone="555-5678",
is_active=True
)
# 5. Mixing order - positional must come before keyword
# ✅ Correct
def calculate(a, b, c):
return a + b + c
print(calculate(1, 2, c=3)) # 6
print(calculate(1, b=2, c=3)) # 6
# ❌ Incorrect - keyword before positional
# print(calculate(a=1, 2, 3)) # SyntaxError
Keyword arguments key points:
- Order doesn't matter — arguments are identified by name
- Self-documenting — makes code more readable
- Positional first — must come after positional arguments
- Improved clarity — especially for functions with many parameters
Quick Check: Do keyword arguments need to be passed in a specific order? (Answer: No, order doesn't matter)
Default Arguments
Arguments with Default Values
# Default arguments are optional parameters with default values
# 1. Basic default arguments
def greet(name, greeting="Hello"):
return f"{greeting}, {name}!"
print(greet("Alice")) # Hello, Alice!
print(greet("Bob", "Hi")) # Hi, Bob!
print(greet(greeting="Hey", name="Charlie")) # Hey, Charlie!
# 2. Multiple default arguments
def create_profile(name, age=0, city="Unknown", occupation="Unemployed"):
return f"{name} ({age}) from {city} - {occupation}"
print(create_profile("Alice")) # Alice (0) from Unknown - Unemployed
print(create_profile("Bob", 25)) # Bob (25) from Unknown - Unemployed
print(create_profile("Charlie", 30, "NYC")) # Charlie (30) from NYC - Unemployed
print(create_profile("Diana", occupation="Engineer")) # Diana (0) from Unknown - Engineer
# 3. Default arguments with mutable values (use with caution)
# ❌ Avoid mutable default arguments
def add_to_list(item, my_list=[]):
my_list.append(item)
return my_list
print(add_to_list(1)) # [1]
print(add_to_list(2)) # [1, 2] ← This is unexpected!
# ✅ Correct way - use None
def add_to_list(item, my_list=None):
if my_list is None:
my_list = []
my_list.append(item)
return my_list
print(add_to_list(1)) # [1]
print(add_to_list(2)) # [2] ← Works as expected!
# 4. Default arguments in real-world scenarios
def calculate_discount(price, discount_percent=10, tax_rate=0.08):
"""Calculate final price with discount and tax"""
discount = price * (discount_percent / 100)
discounted_price = price - discount
tax = discounted_price * tax_rate
return discounted_price + tax
print(calculate_discount(100)) # 97.2 (10% discount, 8% tax)
print(calculate_discount(100, 20)) # 86.4 (20% discount, 8% tax)
print(calculate_discount(100, 15, 0.10)) # 93.5 (15% discount, 10% tax)
# 5. Default arguments with type hints
def format_name(first: str, last: str, middle: str = "") -> str:
"""Format a person's name"""
if middle:
return f"{first} {middle} {last}"
return f"{first} {last}"
print(format_name("John", "Doe")) # John Doe
print(format_name("John", "Doe", "David")) # John David Doe
Default arguments key points:
- Optional — can be omitted when calling the function
- Evaluated once — at function definition time
- Avoid mutable defaults — use None instead of lists/dicts
- Must come after required parameters
- Great for optional behavior — customizable functions
Quick Check: What should you use instead of a mutable default argument? (Answer: None)
Variable-Length Arguments (*args and **kwargs)
Handling Any Number of Arguments
# *args - variable number of positional arguments
# **kwargs - variable number of keyword arguments
# 1. Using *args
def sum_all(*args):
"""Sum any number of arguments"""
return sum(args)
print(sum_all(1, 2, 3)) # 6
print(sum_all(10, 20, 30, 40)) # 100
print(sum_all()) # 0
# 2. Using *args with other parameters
def calculate_total(discount, *prices):
"""Apply discount to all prices"""
subtotal = sum(prices)
discount_amount = subtotal * (discount / 100)
return subtotal - discount_amount
print(calculate_total(10, 100, 200, 300)) # 540 (600 - 60)
print(calculate_total(5, 50, 75)) # 118.75
# 3. Using **kwargs
def print_user_info(**kwargs):
"""Print user information from keyword arguments"""
for key, value in kwargs.items():
print(f"{key}: {value}")
print_user_info(name="Alice", age=25, city="NYC")
# name: Alice
# age: 25
# city: NYC
# 4. Combining *args and **kwargs
def process_data(operation, *args, **kwargs):
"""Process data with any number of arguments"""
print(f"Operation: {operation}")
print(f"Positional args: {args}")
print(f"Keyword args: {kwargs}")
if operation == "sum":
return sum(args)
elif operation == "avg":
return sum(args) / len(args) if args else 0
elif operation == "product":
result = 1
for num in args:
result *= num
return result
return None
print(process_data("sum", 1, 2, 3, 4)) # 10
print(process_data("avg", 10, 20, 30)) # 20.0
print(process_data("product", 2, 3, 4)) # 24
print(process_data("sum", 1, 2, verbose=True, debug=False))
# 5. Unpacking arguments with * and **
def greet(name, age, city):
return f"{name} is {age} years old from {city}"
# Using * to unpack a list
user_data = ["Alice", 25, "NYC"]
print(greet(*user_data)) # Alice is 25 years old from NYC
# Using ** to unpack a dictionary
user_dict = {"name": "Bob", "age": 30, "city": "LA"}
print(greet(**user_dict)) # Bob is 30 years old from LA
# 6. Combining with default parameters
def create_user(username, *args, **kwargs):
"""Create user with any number of additional fields"""
user = {"username": username}
user["additional"] = args
user.update(kwargs)
return user
print(create_user("alice123", "admin", "premium", age=25, city="NYC"))
# {'username': 'alice123', 'additional': ('admin', 'premium'), 'age': 25, 'city': 'NYC'}
*args and **kwargs key points:
- *args — collects extra positional arguments as a tuple
- **kwargs — collects extra keyword arguments as a dictionary
- Flexible — functions can handle any number of arguments
- Unpacking — use * and ** to unpack iterables/dicts
- Common in wrappers — passing arguments through to other functions
Quick Check: What does *args collect as? (Answer: A tuple of positional arguments)
Positional-Only Arguments
Arguments that Must Be Positional
# Positional-only arguments use / in the parameter list
# Introduced in Python 3.8
# 1. Basic positional-only arguments
def greet(name, /, greeting="Hello"):
"""name must be passed positionally"""
return f"{greeting}, {name}!"
# ✅ Valid - name is passed positionally
print(greet("Alice")) # Hello, Alice!
print(greet("Bob", "Hi")) # Hi, Bob!
# ❌ Invalid - name cannot be passed as keyword
# print(greet(name="Charlie")) # TypeError
# 2. Multiple positional-only arguments
def calculate_total(price, quantity, /, tax_rate=0.10):
"""price and quantity must be positional"""
subtotal = price * quantity
tax = subtotal * tax_rate
return subtotal + tax
# ✅ Valid
print(calculate_total(10, 3)) # 33.0
print(calculate_total(10, 3, 0.08)) # 32.4
# ❌ Invalid - price and quantity can't be keywords
# print(calculate_total(price=10, quantity=3)) # TypeError
# 3. Positional-only with both styles
def process_data(data, /, operation="sum", *args, **kwargs):
"""data must be positional, operation is keyword, args and kwargs variable"""
print(f"Data: {data}")
print(f"Operation: {operation}")
print(f"Args: {args}")
print(f"Kwargs: {kwargs}")
return data
# ✅ Valid
process_data("raw_data", operation="avg", 1, 2, 3, verbose=True)
# ❌ Invalid - data can't be keyword
# process_data(data="raw_data") # TypeError
# 4. When to use positional-only arguments
# Use when:
# - The argument name doesn't matter (like in built-in functions)
# - You want to enforce a specific order
# - You're designing low-level APIs
# - You want to allow parameter name changes in the future
# 5. Example from built-in functions
# len() uses positional-only
print(len("hello")) # ✅ Valid
# print(len(obj="hello")) # ❌ Invalid
Positional-only arguments key points:
- Syntax — use / in the parameter list
- Enforces order — arguments must be passed positionally
- API stability — allows parameter name changes
- Examples — used in built-in functions like len()
Quick Check: What symbol indicates positional-only arguments? (Answer: /)
Keyword-Only Arguments
Arguments that Must Be Keyword
# Keyword-only arguments use * in the parameter list
# All arguments after * must be passed as keywords
# 1. Basic keyword-only arguments
def greet(*, name, greeting="Hello"):
"""name and greeting must be passed as keywords"""
return f"{greeting}, {name}!"
# ✅ Valid - both must be keyword
print(greet(name="Alice")) # Hello, Alice!
print(greet(name="Bob", greeting="Hi")) # Hi, Bob!
# ❌ Invalid - name must be keyword
# print(greet("Alice")) # TypeError
# 2. Mixing positional and keyword-only
def create_user(username, age, /, *, city, occupation="Unknown"):
"""username and age are positional, city and occupation are keyword-only"""
return f"{username} ({age}) from {city} - {occupation}"
# ✅ Valid
print(create_user("alice123", 25, city="NYC"))
# alice123 (25) from NYC - Unknown
print(create_user("bob456", 30, city="LA", occupation="Engineer"))
# bob456 (30) from LA - Engineer
# ❌ Invalid - city must be keyword
# print(create_user("charlie789", 35, "Chicago")) # TypeError
# 3. Using * with *args
def process_data(operation, *args, **kwargs):
"""operation is positional, args are variable, kwargs are keyword"""
print(f"Operation: {operation}")
print(f"Args: {args}")
print(f"Kwargs: {kwargs}")
# 4. Keyword-only with default values
def create_profile(name, *, age=0, city="Unknown"):
"""name is positional, age and city are keyword-only"""
return f"{name} is {age} years old from {city}"
print(create_profile("Alice")) # Alice is 0 years old from Unknown
print(create_profile("Bob", age=25)) # Bob is 25 years old from Unknown
print(create_profile("Charlie", age=30, city="NYC")) # Charlie is 30 years old from NYC
# 5. When to use keyword-only arguments
# - When the argument name is important for readability
# - When you want to prevent positional misuse
# - When the argument is optional and has a default
# - When you're designing APIs that should be explicit
# 6. Complete argument order example
def complex_function(a, b, /, c, d, *args, e, f, **kwargs):
"""
Parameter order:
- a, b: positional-only
- c, d: positional or keyword
- *args: variable positional
- e, f: keyword-only
- **kwargs: variable keyword
"""
print(f"a={a}, b={b}, c={c}, d={d}")
print(f"args={args}")
print(f"e={e}, f={f}")
print(f"kwargs={kwargs}")
# ✅ Valid call
complex_function(1, 2, 3, 4, 5, 6, e=7, f=8, g=9, h=10)
Keyword-only arguments key points:
- Syntax — use * in the parameter list
- Enforces keywords — arguments must be passed by name
- Improves readability — makes code self-documenting
- Common with defaults — optional parameters that are clear
Quick Check: What symbol indicates keyword-only arguments? (Answer: *)
Try It Yourself
Experiment with different types of function arguments in the editor below.
FUNCTION ARGUMENTS PRACTICE
========================================
1. POSITIONAL ARGUMENTS
Rectangle 5x3: 15
Rectangle 8x4: 32
2. KEYWORD ARGUMENTS
Hello, Alice!
Hi, Bob?
3. DEFAULT ARGUMENTS
{'username': 'alice123', 'role': 'user', 'active': True}
{'username': 'bob456', 'role': 'admin', 'active': True}
{'username': 'charlie789', 'role': 'user', 'active': False}
4. VARIABLE-LENGTH ARGUMENTS
Summary: {'total': 15, 'average': 3.0, 'metadata': {'name': 'Test', 'source': 'Practice'}}
5. POSITIONAL-ONLY AND KEYWORD-ONLY
a=1, b=2, c=3, d=4, e=5
Function arguments practice complete!
You've Got It!
You now understand all types of function arguments in Python — positional, keyword, default, variable-length, positional-only, and keyword-only arguments.
Quick Quiz
Test what you've learned:
Frequently Asked Questions
What is the difference between *args and **kwargs?
*args collects extra positional arguments as a tuple, while **kwargs collects extra keyword arguments as a dictionary. Both are used to create functions that can handle a variable number of arguments.
Can I use both positional and keyword arguments together?
Why should I avoid mutable default arguments?
What is the difference between positional-only and keyword-only arguments?
What's a common interview question about function arguments?
Can I unpack arguments from a list or dictionary?
* to unpack a list or tuple into positional arguments, and ** to unpack a dictionary into keyword arguments. This is very useful when you have arguments in a collection and want to pass them to a function.
Where to Go From Here
Now that you've mastered function arguments, check out these related topics:
Nesting of Functions
Learn about inner functions and closures.
Learn More →Recursion
Learn about functions that call themselves.
Learn More →Lambda Functions
Learn about anonymous functions and their use cases.
Learn More →