Skip to content
SDETRole
SDETRole

Python interview question

What are *args and **kwargs, and how are they used in test helpers?

beginner 0–2 yrs #functions#args#kwargs#unpacking

Short answer

*args collects extra positional arguments into a tuple and **kwargs collects extra keyword arguments into a dict. The same operators unpack sequences and dicts into calls. They are used for wrappers and decorators that forward arguments, and for builders that accept field overrides.

Answer

*args and **kwargs let a function accept a variable number of arguments. *args gathers any extra positional arguments into a tuple; **kwargs gathers any extra keyword arguments into a dict. The names are only conventions; the * and ** are what matter. The same operators work in reverse at a call site to unpack a sequence or mapping into arguments.

Collecting

def describe(*args, **kwargs):
    print(type(args), args)
    print(type(kwargs), kwargs)

describe(1, 2, browser="firefox", headless=True)
# <class 'tuple'> (1, 2)
# <class 'dict'> {'browser': 'firefox', 'headless': True}

Unpacking

def login(username, password, remember=False): ...

creds = ("qa_user", "s3cret")
options = {"remember": True}
login(*creds, **options)   # login("qa_user", "s3cret", remember=True)

merged = {**default_headers, **{"X-Trace": "abc"}}  # dict merge, later keys win

Parameter order

The full order in a signature is: positional-only, regular, *args, keyword-only, **kwargs.

def request(method, url, /, *args, timeout: float = 10, **kwargs): ...
  • Parameters before / are positional-only (Python 3.8+).
  • Parameters after *args (or a bare *) are keyword-only, which is useful for flags: create_user(name, *, admin=False) forces callers to write admin=True, making tests more readable.

Uses in test code

Builders with overrides

def build_user(**overrides) -> dict:
    user = {
        "email": "qa@example.com",
        "role": "member",
        "active": True,
    }
    unknown = overrides.keys() - user.keys()
    if unknown:
        raise TypeError(f"Unknown fields: {unknown}")
    return {**user, **overrides}

admin = build_user(role="admin")

The guard against unknown keys prevents typos like rol="admin" from silently doing nothing.

Wrappers that forward everything

import functools, logging, time

def timed(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        start = time.perf_counter()
        try:
            return func(*args, **kwargs)
        finally:
            logging.info("%s took %.2fs", func.__name__, time.perf_counter() - start)
    return wrapper

A decorator does not know the wrapped function’s signature, so it accepts and forwards *args, **kwargs. functools.wraps preserves the name and docstring, which matters for pytest reports.

Thin API client methods

class Api:
    def __init__(self, session, base_url):
        self.session, self.base_url = session, base_url

    def get(self, path, **kwargs):
        return self.session.get(f"{self.base_url}{path}", timeout=10, **kwargs)

api.get("/orders", params={"status": "paid"}, headers={"X-Debug": "1"})

Caveats

  • Overusing **kwargs hides the real interface: editors cannot autocomplete and typos go undetected. Prefer explicit parameters for public helpers, and use typing.Unpack with a TypedDict (Python 3.12+) if you need typed kwargs.
  • Passing the same key both explicitly and via **kwargs raises TypeError: got multiple values for keyword argument.

What interviewers look for

  • Tuple versus dict, positional versus keyword.
  • Unpacking at call sites, including dict merging.
  • A real use: decorators forwarding arguments, builders with overrides.
  • Awareness of the readability cost and keyword-only parameters.

A strong answer covers

  • *args collects positional arguments into a tuple
  • **kwargs collects keyword arguments into a dict
  • Unpacking in calls with * and **
  • Forwarding arguments in wrappers and decorators
  • Mentions parameter order or keyword-only and positional-only parameters
Practise answering under time pressure

Type to search across SDETRole.

Full-text search by Pagefind · runs in your browser Open search page →