← Master Index
Vol. 03 Module 3.4 Lecture

*args and **kwargs

Essential Python Skills for AI Engineers (added — needed in practice, not in original outline)

How This Lesson Fits the Module

Module 3.1 covered functions with fixed parameter lists. Real AI libraries—PyTorch, Hugging Face Transformers, FastAPI—expose APIs that accept variable numbers of arguments. *args and **kwargs are the Python mechanisms that make those flexible signatures possible.

When you wrap a model call, build a training utility, or write a decorator, you will often forward arguments you did not explicitly name. Understanding *args and **kwargs is essential for reading library source code and writing reusable AI tooling.

Learning Objectives

By the end of this lesson, students should be able to:

  • Explain how *args collects extra positional arguments into a tuple.
  • Explain how **kwargs collects extra keyword arguments into a dictionary.
  • Unpack sequences and dicts with * and ** at call time.
  • Write wrapper functions that forward arguments to an inner function.
  • Read library signatures like def train(self, *args, **kwargs) confidently.
  • Combine positional-only, keyword-only, *args, and **kwargs in valid orders.

Introduction: Beyond Fixed Parameters

Most beginner functions declare exact parameters: def predict(text, model_id). Library authors cannot predict every argument their users will need—learning rates, random seeds, tokenizer options, HTTP headers. They use *args and **kwargs to accept and forward the rest.

Definition
  • *args — in a definition, gathers extra positional arguments into a tuple named args.
  • **kwargs — in a definition, gathers extra keyword arguments into a dict named kwargs.
  • *iterable / **mapping — in a call, unpacks values into positional or keyword arguments.
def log_and_call(fn, *args, **kwargs):
  print(f"Calling {fn.__name__} with {len(args)} positional args")
  return fn(*args, **kwargs)

def add(a, b, c=0):
  return a + b + c

log_and_call(add, 1, 2, c=3)  # prints then returns 6

Forwarding Arguments in Wrappers

The most common AI-engineering pattern is a wrapper that adds behavior (logging, retries, timing) then passes everything through:

def with_retry(func, *args, max_attempts=3, **kwargs):
    for attempt in range(1, max_attempts + 1):
        try:
            return func(*args, **kwargs)
        except Exception as exc:
            if attempt == max_attempts:
                raise
            print(f"Attempt {attempt} failed: {exc}")

This pattern appears in API clients, database connectors, and training callbacks. The wrapper does not need to know which arguments the inner function accepts.

SyntaxWhereEffect
*argsDefinitionTuple of extra positional values
**kwargsDefinitionDict of extra keyword pairs
*seqCallUnpack sequence as positional args
**dctCallUnpack dict as keyword args
Common Misconception: “The names must be args and kwargs.”

Reality: Only the * and ** matter. def f(*items, **options) is valid. Convention uses args/kwargs for readability.

Common Misconception:**kwargs can pass invalid keyword names to any function.”

Reality: Python still validates the callee’s signature. Passing an unexpected keyword raises TypeError unless the target accepts **kwargs.

Knowledge Check

  1. Short Answer: What type is args inside def f(*args)? Answer: tuple.
  2. True/False: **kwargs must appear after *args in a definition. Answer: True (when both are used).
  3. Write: Unpack params = {"lr": 0.01, "epochs": 5} into train(**params). Answer: train(**params) or train(lr=0.01, epochs=5).
  4. Multiple Choice: Primary use in library code: (a) hide bugs, (b) forward unknown options, (c) replace type hints, (d) avoid imports. Answer: (b).
  5. Short Answer: What type is kwargs inside def f(**kwargs)? Answer: dict.
  6. True/False: The names must literally be args and kwargs. Answer: False—only * and ** matter.
  7. Short Answer: What does *seq do at call time? Answer: Unpacks a sequence into positional arguments.
  8. Multiple Choice: Passing an unexpected keyword to a function without **kwargs: (a) is ignored, (b) raises TypeError, (c) becomes a global, (d) installs a package. Answer: (b).
  9. True/False: A retry wrapper can call func(*args, **kwargs) without knowing the inner signature. Answer: True.
  10. Short Answer: Write a call that unpacks vals = (1, 2) into add. Answer: add(*vals).

Key Takeaways

  • *args and **kwargs collect extra arguments in definitions.
  • Unpacking with * and ** at call time forwards them to other functions.
  • Wrappers, decorators, and library APIs depend on this pattern.
  • Next: Generators & Iterators for memory-efficient iteration over large datasets.
Trainer’s Guide

Source-code walk: Open a Hugging Face from_pretrained wrapper and trace how **kwargs flows to the underlying config. Students see immediate relevance.

Recap: *args and **kwargs collect and forward flexible arguments; next, learn lazy iteration in Generators & Iterators.