Ojasa Mirai

Ojasa Mirai

Python

Loading...

Learning Level

🟢 Beginner🔵 Advanced
Why Functions?Parameters & ArgumentsReturn StatementsScopeDefault ParametersVariable Arguments (*args)Lambda FunctionsDecoratorsFunctional ProgrammingBest Practices
Python/Functions/Keyword Arguments

🔑 Keyword Arguments (**kwargs) — Flexible Named Parameters

Use `**kwargs` to accept any number of named (keyword) arguments. The double asterisk unpacks keyword arguments into a dictionary, enabling functions to accept arbitrary options and configurations. This pattern is essential for building flexible APIs and decorator patterns.


🎯 How **kwargs Works

The `**kwargs` syntax captures all keyword arguments into a dictionary. The double asterisk operator unpacks named arguments, giving you a dictionary where keys are argument names and values are the provided values. This enables accepting unlimited optional configuration options.

def create_config(**settings):
    for key, value in settings.items():
        print(f"{key}: {value}")

create_config(
    model="GPT-4",
    temperature=0.8,
    max_tokens=1000,
    stream=True
)
# Output:
# model: GPT-4
# temperature: 0.8
# max_tokens: 1000
# stream: True

How **kwargs Works Internally

The `` unpacks named arguments into a dictionary**:

def print_kwargs(**kwargs):
    print(f"kwargs type: {type(kwargs)}")
    print(f"kwargs value: {kwargs}")

print_kwargs(name="Alice", age=25, city="NYC")
# Output:
# kwargs type: <class 'dict'>
# kwargs value: {'name': 'Alice', 'age': 25, 'city': 'NYC'}

🔧 Combining with Other Parameters

You can mix required parameters, defaults, `*args`, and `kwargs` together. The order is crucial: required → default → *args → kwargs.

def flexible_function(required, default_arg="default", *args, **kwargs):
    print(f"Required: {required}")
    print(f"Default: {default_arg}")
    print(f"Args: {args}")
    print(f"Kwargs: {kwargs}")

flexible_function("value", "custom", 1, 2, 3, name="test", debug=True)
# Output:
# Required: value
# Default: custom
# Args: (1, 2, 3)
# Kwargs: {'name': 'test', 'debug': True}

Order matters: required → default → *args → **kwargs


💡 Real-World Examples

Configuration Builder

Configuration systems use **kwargs extensively to accept arbitrary options while maintaining clean APIs.

def build_api_client(
    base_url,
    timeout=30,
    **config
):
    """Build API client with flexible configuration."""
    client_config = {
        "base_url": base_url,
        "timeout": timeout,
        **config  # Merge additional config options
    }
    return client_config

# Various usage patterns
config1 = build_api_client("https://api.example.com")
config2 = build_api_client("https://api.example.com", timeout=60, retries=3)
config3 = build_api_client(
    "https://api.example.com",
    auth_type="bearer",
    ssl_verify=False
)

Logger Function

Logging systems benefit from **kwargs to accept flexible metadata:

def log_event(event_type, *details, **metadata):
    """Log an event with flexible details and metadata."""
    print(f"Event: {event_type}")
    if details:
        print(f"  Details: {details}")
    if metadata:
        print(f"  Metadata: {metadata}")

log_event(
    "user_login",
    "admin",
    "success",
    timestamp=1234567890,
    ip="192.168.1.1"
)
# Output:
# Event: user_login
#   Details: ('admin', 'success')
#   Metadata: {'timestamp': 1234567890, 'ip': '192.168.1.1'}

Function Wrapper

Wrapper functions use **kwargs to forward arguments transparently:

def call_function_multiple_times(func, times, *args, **kwargs):
    """Call a function multiple times with same arguments."""
    results = []
    for _ in range(times):
        result = func(*args, **kwargs)
        results.append(result)
    return results

def add(a, b):
    return a + b

results = call_function_multiple_times(add, 3, 5, 3)
print(results)  # [8, 8, 8]

🎨 Processing **kwargs

Extracting Specific Keys

def process_user(name, **options):
    """Process user with flexible options."""
    # Extract with defaults
    age = options.get('age', 18)
    role = options.get('role', 'user')
    active = options.get('active', True)

    return {
        "name": name,
        "age": age,
        "role": role,
        "active": active
    }

user1 = process_user("Alice")
user2 = process_user("Bob", age=25, role="admin")

Type-Checked kwargs

def create_record(**kwargs) -> dict:
    """Create record with type checking."""
    allowed_keys = {'id', 'name', 'email', 'age'}

    # Validate keys
    invalid = set(kwargs.keys()) - allowed_keys
    if invalid:
        raise ValueError(f"Invalid keys: {invalid}")

    return kwargs

# Valid
record = create_record(id=1, name="Alice", email="alice@example.com")

# Invalid - will raise error
# record = create_record(id=1, invalid_key="value")

Merging Configurations

def merge_configs(base_config, **overrides):
    """Merge base config with overrides."""
    config = base_config.copy()
    config.update(overrides)
    return config

defaults = {"timeout": 30, "retries": 3, "ssl": True}
custom = merge_configs(defaults, timeout=60, new_option="value")
# Result: {'timeout': 60, 'retries': 3, 'ssl': True, 'new_option': 'value'}

🚀 Advanced Patterns

Decorator with Options

def retry_decorator(max_attempts=3, delay=1, **options):
    """Decorator that retries function with options."""
    def decorator(func):
        def wrapper(*args, **kwargs):
            import time
            for attempt in range(max_attempts):
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    if attempt == max_attempts - 1:
                        raise
                    time.sleep(delay)
                    print(f"Retry {attempt + 1}/{max_attempts}")
        return wrapper
    return decorator

@retry_decorator(max_attempts=3, delay=0.5, verbose=True)
def unreliable_operation():
    import random
    if random.random() < 0.7:
        raise Exception("Failed")
    return "Success"

Building Dynamic Classes

def create_class(name, methods=None, **attributes):
    """Dynamically create a class with attributes and methods."""
    if methods is None:
        methods = {}

    # Combine attributes and methods
    namespace = {**attributes, **methods}

    return type(name, (), namespace)

# Create class dynamically
Point = create_class(
    "Point",
    x=0,
    y=0,
    info=lambda self: f"({self.x}, {self.y})"
)

p = Point()
print(p.info())  # (0, 0)

⚠️ Common Patterns and Best Practices

Check for Required Options

def api_call(url, method="GET", **options):
    """Make API call with required and optional parameters."""
    required = {'timeout', 'retries'}
    provided = set(options.keys())

    missing = required - provided
    if missing:
        raise TypeError(f"Missing required options: {missing}")

    return {"url": url, "method": method, **options}

# Valid
result = api_call("https://api.example.com", timeout=30, retries=3)

# Invalid - missing required options
# api_call("https://api.example.com")

Unpacking Dictionaries in Calls

You can unpack dictionaries when calling functions:

def create_user(name, age, email):
    return {"name": name, "age": age, "email": email}

user_data = {"name": "Alice", "age": 25, "email": "alice@example.com"}
user = create_user(**user_data)  # Unpacks dict as kwargs

🔑 Key Takeaways

ConceptRemember
**kwargsCapture variable keyword arguments
DictionaryArguments collected into dictionary
OrderRequired → default → *args → **kwargs
AccessUse .get(), .items(), or direct keys
Flexible APIsPerfect for configuration and options
UnpackingUse `**dict` to unpack in calls

🔗 What's Next?

You now understand all parameter types! Let's combine them in powerful patterns.

Back to Functions Overview →


Ready to practice? Try advanced challenges


Resources

Python Docs

Ojasa Mirai

Master AI-powered development skills through structured learning, real projects, and verified credentials. Whether you're upskilling your team or launching your career, we deliver the skills companies actually need.

Learn Deep • Build Real • Verify Skills • Launch Forward

Courses

PythonFastapiReactJSCloud

© 2026 Ojasa Mirai. All rights reserved.

TwitterGitHubLinkedIn