A visual guide to understanding different types of Python function arguments with simple code examples.
Master Python function arguments from basic to advanced with simple explanations, interactive examples, and practical quizzes
Imagine you’re ordering pizza. You don’t just say “I want pizza.” You tell them the size, toppings, crust type, and delivery address. Function arguments work the same way – they’re the details that make your functions actually useful!
Function arguments are like ingredients in a recipe. You give your function these ingredients, and it creates something amazing. In Python, there are different ways to pass these ingredients, and knowing them all makes you a much better programmer.
Think about it this way: A function without arguments is like a vending machine that only gives you one type of snack. But a function with arguments? That’s like having a personal chef who can make anything you want!
When you define and call functions in Python, understanding arguments becomes super important. It’s the difference between writing rigid code and flexible, reusable code.
Positional arguments are like standing in line at a coffee shop. The order matters! First person gets served first, second person gets served second. Same with positional arguments – first argument goes to first parameter, second to second, and so on.
Here’s the most basic example:
def introduce_person(name, age):
return f"Hi! I'm {name} and I'm {age} years old."
# Calling with positional arguments
result = introduce_person("Sarah", 25)
print(result) See how “Sarah” automatically went to the name parameter and 25 went to the age parameter? That’s because of their position!
Let’s see what happens when we mess up the order:
# Oops! Wrong order
result = introduce_person(25, "Sarah")
print(result) That doesn’t make sense! This shows why order matters with positional arguments.
Let’s create something more practical:
def calculate_rectangle_area(length, width):
"""Calculate the area of a rectangle"""
area = length * width
return f"A rectangle with length {length} and width {width} has area {area}"
# Different rectangles
print(calculate_rectangle_area(10, 5))
print(calculate_rectangle_area(7, 3))
print(calculate_rectangle_area(15, 8)) Keyword arguments are like labeled boxes. Instead of guessing what goes where based on order, you put a label on each value. This makes your code much clearer and less error-prone.
Think of it like ordering at a restaurant where you can say “I want the pasta with extra cheese and no mushrooms” instead of just saying “pasta, cheese, no mushrooms” and hoping they understand the order.
def create_profile(name, age, city, hobby):
return f"{name} is {age} years old, lives in {city}, and loves {hobby}."
# Using keyword arguments - order doesn't matter!
profile1 = create_profile(age=28, name="Alex", hobby="reading", city="New York")
profile2 = create_profile(city="Paris", hobby="cooking", name="Marie", age=32)
print(profile1)
print(profile2) Notice how we mixed up the order completely, but Python still understood exactly what we meant because we used the parameter names!
You can use both types together, but there’s an important rule: positional arguments must come first.
def book_flight(destination, departure_date, seat_class, meal_preference):
return f"Flight to {destination} on {departure_date}, {seat_class} class, {meal_preference} meal"
# Mixing positional and keyword arguments
flight1 = book_flight("Tokyo", "2024-07-15", seat_class="business", meal_preference="vegetarian")
flight2 = book_flight("London", departure_date="2024-08-20", seat_class="economy", meal_preference="regular")
print(flight1)
print(flight2) This will cause an error because keyword arguments must come after positional ones:
# This will cause a SyntaxError!
# flight = book_flight(destination="Rome", "2024-09-10", "economy", "halal")
# ERROR: positional argument follows keyword argument Understanding how to use function parameters and return values in Python becomes much easier when you master keyword arguments. They make your functions more readable and user-friendly.
Default arguments are like having a smart assistant who knows your usual preferences. If you don’t specify something, they use what you normally like. If you do specify, they use your new choice.
Think of default arguments like your favorite coffee order. If you walk into your regular coffee shop and just say “the usual,” they know what to make. But if you want something different today, you can still specify exactly what you want.
def greet_customer(name, greeting="Hello", punctuation="!"):
return f"{greeting}, {name}{punctuation}"
# Using default values
print(greet_customer("Alice"))
# Changing just the greeting
print(greet_customer("Bob", "Hi"))
# Changing both optional parameters
print(greet_customer("Charlie", "Hey", ".."))
# Using keyword arguments to skip the middle parameter
print(greet_customer("Diana", punctuation="!!!")) Let’s create a function that sends emails with smart defaults:
def send_email(recipient, subject, message, sender="noreply@company.com", priority="normal"):
"""Send an email with default sender and priority"""
email_info = {
"to": recipient,
"from": sender,
"subject": subject,
"message": message,
"priority": priority
}
return f"Email sent!\\nTo: {recipient}\\nFrom: {sender}\\nSubject: {subject}\\nPriority: {priority}\\nMessage: {message}"
# Simple email with defaults
print(send_email("alice@example.com", "Meeting Tomorrow", "Don't forget our 2 PM meeting!"))
print("\\n" + "="*50 + "\\n")
# High priority email with custom sender
print(send_email(
"bob@example.com",
"URGENT: Server Down",
"The main server is down. Please check immediately!",
sender="admin@company.com",
priority="high"
)) Let’s create a game character with default stats:
def create_character(name, character_class="Warrior", health=100, mana=50, level=1):
return {
"name": name,
"class": character_class,
"health": health,
"mana": mana,
"level": level
}
# Quick warrior with defaults
hero1 = create_character("Aragorn")
print(f"Hero 1: {hero1}")
# Custom mage
hero2 = create_character("Gandalf", "Mage", health=80, mana=150)
print(f"Hero 2: {hero2}")
# Experienced archer
hero3 = create_character("Legolas", character_class="Archer", level=5)
print(f"Hero 3: {hero3}") Sometimes you don’t know how many arguments someone will give your function. It’s like being a waiter who doesn’t know if a table will order 2 dishes or 10 dishes. That’s where *args comes in handy!
The *args (which stands for “arguments”) lets your function accept any number of positional arguments. Think of it as a magic bag that can hold as many items as you throw into it.
def add_numbers(*numbers):
"""Add any number of numbers together"""
total = 0
for num in numbers:
total += num
return total
# You can pass any number of arguments!
print(add_numbers(5)) # One number
print(add_numbers(5, 10)) # Two numbers
print(add_numbers(1, 2, 3, 4, 5)) # Five numbers
print(add_numbers(10, 20, 30, 40, 50, 60)) # Six numbers See how the same function handled 1 number, 2 numbers, 5 numbers, and 6 numbers? That’s the power of *args!
Let’s peek inside to see what *args actually contains:
def examine_args(*args):
print(f"Type of args: {type(args)}")
print(f"Args contains: {args}")
print(f"Number of arguments: {len(args)}")
for i, arg in enumerate(args):
print(f" Argument {i+1}: {arg}")
examine_args("apple", "banana", "cherry") *args creates a tuple containing all the extra arguments. Pretty cool, right?
def create_shopping_list(store_name, *items):
"""Create a shopping list for a specific store"""
print(f"Shopping List for {store_name}:")
print("-" * 30)
if not items:
print("No items in the list yet!")
else:
for i, item in enumerate(items, 1):
print(f"{i}. {item}")
# Different shopping lists
create_shopping_list("Walmart")
print()
create_shopping_list("Target", "milk", "bread", "eggs")
print()
create_shopping_list("Whole Foods", "organic apples", "quinoa", "almond milk", "kale", "avocados") Let’s create a function that calculates statistics for any number of test scores:
def calculate_stats(student_name, *scores):
"""Calculate statistics for a student's test scores"""
if not scores:
return f"{student_name} has no scores recorded yet."
total_scores = len(scores)
total_points = sum(scores)
average = total_points / total_scores
highest = max(scores)
lowest = min(scores)
result = f"""
Student: {student_name}
Number of tests: {total_scores}
Scores: {', '.join(map(str, scores))}
Average: {average:.1f}
Highest: {highest}
Lowest: {lowest}
"""
return result.strip()
# Different students with different numbers of tests
print(calculate_stats("Alice", 85, 92, 78, 96))
print("\n" + "="*40 + "\n")
print(calculate_stats("Bob", 90, 88))
print("\n" + "="*40 + "\n")
print(calculate_stats("Charlie")) If *args is like a magic bag for regular arguments, then **kwargs is like a magic filing cabinet for labeled arguments. The “kwargs” stands for “keyword arguments,” and it can handle any number of named parameters you throw at it!
Imagine you’re ordering a custom pizza and you can specify any topping you want: extra_cheese=True, pepperoni=False, mushrooms=True, pineapple=True (yes, some people like it!). **kwargs works exactly like that.
def create_user_profile(**details):
"""Create a user profile with any details provided"""
print("User Profile:")
print("-" * 20)
if not details:
print("No details provided!")
else:
for key, value in details.items():
print(f"{key.replace('_', ' ').title()}: {value}")
# Create different profiles with different information
create_user_profile(name="Alice", age=25, city="New York")
print()
create_user_profile(username="bob123", email="bob@email.com", favorite_color="blue", pet_name="Max")
print()
create_user_profile(first_name="Charlie", last_name="Brown", occupation="Teacher", hobbies="Reading, Swimming", phone="555-0123") Let’s see what **kwargs actually contains:
def examine_kwargs(**kwargs):
print(f"Type of kwargs: {type(kwargs)}")
print(f"Kwargs contains: {kwargs}")
print(f"Number of keyword arguments: {len(kwargs)}")
for key, value in kwargs.items():
print(f" {key} = {value} (type: {type(value).__name__})")
examine_kwargs(name="Diana", age=30, is_student=True, grades=[85, 92, 78]) **kwargs creates a dictionary where the keys are the parameter names and the values are what you passed in!
def configure_database(database_name, **settings):
"""Configure a database with custom settings"""
print(f"Configuring database: {database_name}")
print("Settings:")
# Default settings
default_settings = {
'host': 'localhost',
'port': 5432,
'timeout': 30,
'auto_commit': True
}
# Update defaults with provided settings
default_settings.update(settings)
for setting, value in default_settings.items():
print(f" {setting}: {value}")
return default_settings
# Basic configuration with defaults
print("=== Basic Setup ===")
config1 = configure_database("user_data")
print()
# Custom configuration
print("=== Custom Setup ===")
config2 = configure_database(
"inventory",
host="192.168.1.100",
port=3306,
timeout=60,
ssl_enabled=True,
backup_enabled=True
) Let’s build a pizza ordering system that can handle any combination of toppings:
def order_pizza(size, crust="regular", **toppings):
"""Order a pizza with any toppings you want"""
base_prices = {'small': 8.99, 'medium': 12.99, 'large': 16.99}
topping_prices = {
'cheese': 1.50, 'pepperoni': 2.00, 'mushrooms': 1.75,
'olives': 1.25, 'pineapple': 1.50, 'bacon': 2.50
}
print(f"PIZZA ORDER")
print(f"Size: {size.title()}")
print(f"Crust: {crust.title()}")
total_price = base_prices.get(size.lower(), 12.99)
if toppings:
print("Toppings:")
for topping, quantity in toppings.items():
if quantity: # Only add if quantity is not 0 or False
topping_name = topping.replace('_', ' ').title()
if isinstance(quantity, bool) and quantity:
print(f" - {topping_name}")
total_price += topping_prices.get(topping, 1.00)
elif isinstance(quantity, int) and quantity > 0:
print(f" - {topping_name} (x{quantity})")
total_price += topping_prices.get(topping, 1.00) * quantity
else:
print("No extra toppings (plain pizza)")
print(f"\\nTotal Price: ${total_price:.2f}")
return total_price
# Different pizza orders
order_pizza("medium", pepperoni=True, cheese=True, mushrooms=True)
print("\\n" + "="*40 + "\\n")
order_pizza("large", "thin", bacon=2, pineapple=True, olives=False)
print("\\n" + "="*40 + "\\n")
order_pizza("small") **kwargs is especially useful when you’re building APIs or working with configuration files. It’s similar to how building web applications with Flask often requires flexible parameter handling.
Now comes the exciting part! You can combine all these different argument types in a single function. But there’s a specific order you must follow – it’s like getting dressed in the morning. You wouldn’t put your shoes on before your socks, right?
When combining different argument types, you must follow this exact order:
def ultimate_function(required_arg, *args, default_arg="default", **kwargs):
"""A function that demonstrates all argument types"""
print("=== ULTIMATE FUNCTION CALL ===")
print(f"Required argument: {required_arg}")
if args:
print(f"Extra positional arguments (*args): {args}")
else:
print("No extra positional arguments")
print(f"Default argument: {default_arg}")
if kwargs:
print("Extra keyword arguments (**kwargs):")
for key, value in kwargs.items():
print(f" {key}: {value}")
else:
print("No extra keyword arguments")
# Test 1: Just the required argument
print("TEST 1:")
ultimate_function("I'm required!")
print()
# Test 2: Required + extra positional
print("TEST 2:")
ultimate_function("Still required", "extra1", "extra2", 42)
print()
# Test 3: All types together
print("TEST 3:")
ultimate_function(
"Required value", # required_arg
"bonus1", "bonus2", # *args
default_arg="custom default", # keyword argument
name="Alice", # **kwargs
age=25, # **kwargs
city="New York" # **kwargs
) This flexible approach to function parameters is what makes Python so powerful. When you understand how to properly handle errors in your functions, like in mastering file handling and error management, combining it with flexible arguments creates robust, professional code.
Now that you’ve mastered the basics, let’s dive into some advanced techniques that professional Python developers use. These are the secret weapons that separate beginners from experts!
Python 3.8 introduced special syntax to force arguments to be positional-only or keyword-only. This gives you more control over how your functions are called.
def advanced_function(pos_only1, pos_only2, /, normal_arg, *, kw_only1, kw_only2):
"""
- pos_only1, pos_only2: Must be passed as positional arguments
- normal_arg: Can be positional or keyword
- kw_only1, kw_only2: Must be passed as keyword arguments
"""
return f"pos_only: {pos_only1}, {pos_only2} | normal: {normal_arg} | kw_only: {kw_only1}, {kw_only2}"
# This works - correct usage
result = advanced_function("a", "b", "c", kw_only1="d", kw_only2="e")
print("✅ Correct usage:")
print(result)
print()
# This also works - normal_arg as keyword
result2 = advanced_function("a", "b", normal_arg="c", kw_only1="d", kw_only2="e")
print("✅ Also correct:")
print(result2)
# These would cause errors:
# advanced_function(pos_only1="a", pos_only2="b", "c", kw_only1="d", kw_only2="e") # Error!
# advanced_function("a", "b", "c", "d", "e") # Error! You can unpack lists and dictionaries directly into function calls. This is super useful when you have data stored in collections!
def create_person(name, age, city, occupation="Student"):
return f"{name} is a {age}-year-old {occupation} from {city}"
# Data stored in different formats
person_data_list = ["Alice", 25, "New York"]
person_data_dict = {"name": "Bob", "age": 30, "city": "London", "occupation": "Engineer"}
# Unpacking list with *
print("From list:")
print(create_person(*person_data_list))
# Unpacking dictionary with **
print("\\nFrom dictionary:")
print(create_person(**person_data_dict))
# Mixed unpacking
extra_info = {"city": "Paris", "occupation": "Artist"}
print("\\nMixed approach:")
print(create_person("Charlie", 28, **extra_info)) Understanding these advanced concepts helps when working with Python’s built-in functions like the Python id() function and the Python type() function, which themselves use flexible argument patterns.
Time to put your knowledge to the test! Don’t worry if you don’t get them all right the first time – that’s how we learn!
Want more practice? Check out our comprehensive Python coding quiz for additional challenges!
Here are the questions that almost every Python learner asks about function arguments:
Absolutely! You can use both *args and **kwargs in the same function. Just remember the order: regular arguments, *args, keyword arguments with defaults, then **kwargs.
Example: def my_func(required, *args, default="value", **kwargs):
No! The magic is in the asterisks (* and **), not the names. You could use *numbers, *items, **options, **settings, etc. But “args” and “kwargs” are standard conventions that every Python developer recognizes, so it’s best to stick with them.
Nothing breaks! If no extra positional arguments are passed, *args becomes an empty tuple. If no extra keyword arguments are passed, **kwargs becomes an empty dictionary. Your function should handle these empty cases gracefully.
*args is a tuple, so you can’t modify it directly (tuples are immutable). However, **kwargs is a dictionary, so you can add, remove, or modify its contents. But be careful – changes to **kwargs won’t affect the original variables passed to your function.
Use positional arguments for values that are always required and have an obvious order (like coordinates: x, y). Use keyword arguments when you have many parameters, when the meaning isn’t obvious from position, or when you want to make some parameters optional.
Parameters are the variables in the function definition (like variables in a recipe). Arguments are the actual values you pass when calling the function (like the actual ingredients you use). So in def greet(name):, “name” is a parameter. In greet("Alice"), “Alice” is an argument.
Technically yes, but it’s usually a bad idea! Python evaluates default arguments once when the function is defined, not each time it’s called. This means if you use a list as a default and modify it, the changes persist between function calls. Use None as default and create the list inside the function instead.
Python has a limit of 255 parameters per function. But in practice, if you need more than 5-10 parameters, you should probably reconsider your function design. Consider using a dictionary, a class, or breaking the function into smaller pieces.
After debugging production systems that process millions of records daily and optimizing research pipelines that…
The landscape of Business Intelligence (BI) is undergoing a fundamental transformation, moving beyond its historical…
The convergence of artificial intelligence and robotics marks a turning point in human history. Machines…
The journey from simple perceptrons to systems that generate images and write code took 70…
In 1973, the British government asked physicist James Lighthill to review progress in artificial intelligence…
Expert systems came before neural networks. They worked by storing knowledge from human experts as…
This website uses cookies.