Daily Tech Brief

Top startup stories in your inbox

Subscribe Free

© 2026 rakrisi Daily

Advanced Functions - Args, Kwargs, and More

Advanced Functions: Args, Kwargs, and Function Flexibility

Welcome to advanced function techniques! Now that you know the basics, let’s make functions that can handle any number of arguments and be incredibly flexible.

Variable-Length Arguments (*args)

The Problem: Fixed Number of Parameters

# ❌ Limited function - only works with exactly 2 numbers
def add_two_numbers(a, b):
    return a + b

print(add_two_numbers(5, 3))  # 8
# add_two_numbers(1, 2, 3)  # Error: too many arguments!

The Solution: *args

# ✅ Flexible function - works with any number of arguments
def add_numbers(*args):
    """Add any number of numbers together."""
    total = 0
    for number in args:
        total += number
    return total

print(add_numbers(5, 3))           # 8
print(add_numbers(1, 2, 3, 4, 5))  # 15
print(add_numbers(10))              # 10
print(add_numbers())                # 0

Real-Life Example: Pizza Toppings

def make_pizza(size, *toppings):
    """Make a pizza with any number of toppings."""
    print(f"Making a {size} pizza with the following toppings:")
    if not toppings:
        print("  - Just cheese")
    else:
        for topping in toppings:
            print(f"  - {topping}")
    print("🍕 Pizza is ready!")

# Different pizza orders
make_pizza("large", "pepperoni", "mushrooms", "olives")
make_pizza("medium", "cheese")  # No extra toppings
make_pizza("small", "hawaiian", "extra cheese", "pineapple", "ham")

*args is a Tuple

def print_args_info(*args):
    """Demonstrate that *args is a tuple."""
    print(f"Type of args: {type(args)}")
    print(f"Args content: {args}")
    print(f"Number of args: {len(args)}")

    if args:
        print(f"First arg: {args[0]}")
        print(f"Last arg: {args[-1]}")

print_args_info(1, 2, 3, "hello", True)

Keyword Arguments (**kwargs)

The Problem: Too Many Optional Parameters

# ❌ Hard to maintain with many optional parameters
def create_user(name, age=None, email=None, phone=None, address=None):
    user = {"name": name}
    if age: user["age"] = age
    if email: user["email"] = email
    if phone: user["phone"] = phone
    if address: user["address"] = address
    return user

# Usage is okay, but adding new fields requires changing the function
user1 = create_user("Alice", age=25, email="alice@email.com")

The Solution: **kwargs

# ✅ Flexible - can add any number of keyword arguments
def create_user(name, **kwargs):
    """Create a user with any additional attributes."""
    user = {"name": name}
    user.update(kwargs)  # Add all keyword arguments
    return user

# Now you can add any fields without changing the function!
user1 = create_user("Alice", age=25, email="alice@email.com")
user2 = create_user("Bob", age=30, email="bob@email.com", phone="555-0123", department="Engineering")
user3 = create_user("Charlie", hobbies=["reading", "coding"], favorite_color="blue")

print(user1)
print(user2)
print(user3)

Real-Life Example: Custom Sandwich Maker

def make_sandwich(bread_type, **ingredients):
    """Make a custom sandwich with any ingredients."""
    print(f"🍞 Making a {bread_type} sandwich with:")

    if not ingredients:
        print("  - Just bread (very plain!)")
    else:
        for ingredient, amount in ingredients.items():
            print(f"  - {amount} {ingredient}")

    print("🥪 Sandwich complete!")

# Different sandwich orders
make_sandwich("whole wheat", lettuce="leafy greens", tomato="slices", cheese="cheddar", mayo="spread")
make_sandwich("sourdough", turkey="slices", avocado="mashed", bacon="strips")
make_sandwich("rye")  # Plain sandwich

**kwargs is a Dictionary

def print_kwargs_info(**kwargs):
    """Demonstrate that **kwargs is a dictionary."""
    print(f"Type of kwargs: {type(kwargs)}")
    print(f"Kwargs content: {kwargs}")
    print(f"Number of kwargs: {len(kwargs)}")

    for key, value in kwargs.items():
        print(f"  {key}: {value}")

print_kwargs_info(name="Alice", age=25, city="New York", hobbies=["reading", "coding"])

Combining Regular Parameters with *args and **kwargs

Order Matters!

# ✅ Correct order: required → *args → **kwargs
def flexible_function(required_param, *args, **kwargs):
    print(f"Required: {required_param}")
    print(f"Args: {args}")
    print(f"Kwargs: {kwargs}")

flexible_function("hello", 1, 2, 3, name="Alice", age=25)

# ❌ Wrong order - this will cause a SyntaxError
# def wrong_order(*args, required_param, **kwargs):
#     pass

Real-Life Example: Order Food

def order_food(main_dish, *side_dishes, **customizations):
    """Place a food order with customizations."""
    print(f"🍽️  Ordering {main_dish}")

    if side_dishes:
        print("Side dishes:")
        for side in side_dishes:
            print(f"  - {side}")

    if customizations:
        print("Customizations:")
        for item, instruction in customizations.items():
            print(f"  - {item}: {instruction}")

    print("Order placed! ✅")

# Different orders
order_food("steak", "mashed potatoes", "green beans",
           steak="medium rare", potatoes="extra butter")

order_food("salad", "breadsticks",
           dressing="ranch", extra_cheese=True)

order_food("pasta")  # Simple order

Unpacking Arguments

Unpacking Lists/Tuples with *

def add_three_numbers(a, b, c):
    return a + b + c

# Regular call
result1 = add_three_numbers(1, 2, 3)
print(result1)  # 6

# Unpack a list/tuple
numbers = [4, 5, 6]
result2 = add_three_numbers(*numbers)  # Unpacks to: add_three_numbers(4, 5, 6)
print(result2)  # 15

# Unpack a tuple
coords = (10, 20, 30)
result3 = add_three_numbers(*coords)
print(result3)  # 60

Unpacking Dictionaries with **

def create_profile(name, age, city, profession):
    return f"{name} is {age} years old, lives in {city}, and works as a {profession}."

# Regular call
profile1 = create_profile("Alice", 25, "New York", "engineer")
print(profile1)

# Unpack a dictionary
person = {
    "name": "Bob",
    "age": 30,
    "city": "London",
    "profession": "designer"
}
profile2 = create_profile(**person)  # Unpacks to keyword arguments
print(profile2)

Real-Life Example: Database Query Builder

def build_query(table, **filters):
    """Build a database query with filters."""
    query = f"SELECT * FROM {table}"

    if filters:
        conditions = []
        for field, value in filters.items():
            conditions.append(f"{field} = '{value}'")
        query += " WHERE " + " AND ".join(conditions)

    return query

# Build different queries
query1 = build_query("users", active=True, role="admin")
print(query1)  # "SELECT * FROM users WHERE active = 'True' AND role = 'admin'"

query2 = build_query("products", category="electronics", in_stock=True)
print(query2)  # "SELECT * FROM products WHERE category = 'electronics' AND in_stock = 'True'"

query3 = build_query("orders")  # No filters
print(query3)  # "SELECT * FROM orders"

Advanced Examples

Example 1: Flexible Calculator

def calculator(operation, *numbers, **options):
    """Perform calculations with flexible arguments."""
    if not numbers:
        return "Error: No numbers provided"

    result = numbers[0]

    # Apply operation to all numbers
    for num in numbers[1:]:
        if operation == "add":
            result += num
        elif operation == "multiply":
            result *= num
        elif operation == "subtract":
            result -= num
        elif operation == "divide":
            if num == 0:
                return "Error: Division by zero"
            result /= num
        else:
            return f"Error: Unknown operation '{operation}'"

    # Apply options
    if "round" in options:
        result = round(result, options["round"])

    if "absolute" in options and options["absolute"]:
        result = abs(result)

    return result

# Test the calculator
print(calculator("add", 1, 2, 3, 4, 5))                    # 15
print(calculator("multiply", 2, 3, 4))                      # 24
print(calculator("divide", 100, 2, 2, round=2))             # 25.0
print(calculator("subtract", 100, 20, 30, absolute=True))   # 50

Example 2: HTML Tag Generator

def create_html_tag(tag_name, content="", **attributes):
    """Create an HTML tag with attributes."""
    # Build attribute string
    attr_string = ""
    if attributes:
        attr_list = []
        for attr, value in attributes.items():
            attr_list.append(f'{attr}="{value}"')
        attr_string = " " + " ".join(attr_list)

    # Create the tag
    if content:
        html = f"<{tag_name}{attr_string}>{content}</{tag_name}>"
    else:
        html = f"<{tag_name}{attr_string} />"

    return html

# Create different HTML elements
div = create_html_tag("div", "Hello World", class_="greeting", id="main")
print(div)  # <div class="greeting" id="main">Hello World</div>

link = create_html_tag("a", "Click me", href="https://example.com", target="_blank")
print(link)  # <a href="https://example.com" target="_blank">Click me</a>

img = create_html_tag("img", src="image.jpg", alt="A picture", width="300")
print(img)  # <img src="image.jpg" alt="A picture" width="300" />

Example 3: Logger Function

def log_message(level, message, *args, **context):
    """Log a message with flexible formatting and context."""
    # Format the message with args if provided
    if args:
        message = message.format(*args)

    # Build log entry
    timestamp = "2024-01-15 10:30:00"  # In real code, use datetime
    log_entry = f"[{timestamp}] {level.upper()}: {message}"

    # Add context information
    if context:
        context_info = ", ".join(f"{k}={v}" for k, v in context.items())
        log_entry += f" ({context_info})"

    print(log_entry)
    return log_entry

# Different log messages
log_message("info", "User {} logged in", "alice123", user_id=123, ip="192.168.1.1")
log_message("error", "Database connection failed", attempt=3, error_code="ECONNREFUSED")
log_message("debug", "Processing completed", duration="2.5s", records_processed=1500)

Function Introspection

Inspecting Function Signatures

import inspect

def example_function(a, b=10, *args, **kwargs):
    """An example function with various parameter types."""
    pass

# Get function signature
sig = inspect.signature(example_function)
print(f"Function signature: {sig}")

# Get parameters
params = sig.parameters
print("Parameters:")
for name, param in params.items():
    print(f"  {name}: {param}")

Best Practices

1. Use Descriptive Parameter Names

# ❌ Not descriptive
def calc(x, y, z):
    pass

# ✅ Descriptive
def calculate_total(price, tax_rate, discount_percent):
    pass

2. Document Your Functions

def process_data(data, *filters, **options):
    """
    Process data with optional filters and options.

    Args:
        data: The data to process
        *filters: Variable number of filter functions to apply
        **options: Keyword options for processing

    Returns:
        Processed data

    Examples:
        process_data(my_data, filter1, filter2, sort=True, reverse=False)
    """
    pass

3. Validate Arguments

def divide_numbers(dividend, *divisors):
    """Divide a number by multiple divisors."""
    if not divisors:
        raise ValueError("At least one divisor required")

    result = dividend
    for divisor in divisors:
        if divisor == 0:
            raise ValueError("Cannot divide by zero")
        result /= divisor

    return result

# Test validation
try:
    result = divide_numbers(100, 2, 5)
    print(f"Result: {result}")
except ValueError as e:
    print(f"Error: {e}")

Practice Exercises

Exercise 1: Flexible Shopping List

Create a shopping list function that accepts:

  • Required: list name
  • *args: items to add
  • **kwargs: item quantities

Exercise 2: Custom Formatter

Create a text formatting function that accepts:

  • Required: text to format
  • *args: formatting operations (uppercase, lowercase, capitalize, etc.)
  • **kwargs: additional formatting options (color, style, etc.)

Exercise 3: Database Query Builder

Create a query builder that accepts:

  • Required: table name
  • *args: columns to select
  • **kwargs: WHERE conditions

Exercise 4: Report Generator

Create a report generator that accepts:

  • Required: report title
  • *args: data sections
  • **kwargs: report options (format, include_charts, etc.)

Exercise 5: API Request Builder

Create an API request function that accepts:

  • Required: endpoint URL
  • *args: path parameters
  • **kwargs: query parameters and headers

Summary

Advanced functions give you incredible flexibility:

  • *args: Accept any number of positional arguments (as a tuple)
  • **kwargs: Accept any number of keyword arguments (as a dictionary)
  • Unpacking: Use * and ** to unpack iterables into arguments
  • Parameter order: required → *args**kwargs

These techniques allow you to create functions that can handle:

  • Variable numbers of arguments
  • Optional parameters without function changes
  • Complex configuration options
  • API-like interfaces

Next: Lambda Functions - anonymous functions for simple tasks! 🚀