TL;DR: Using parameter kinds and type annotation goes a long way toward creating clear, robust programs and APIs. Best practices:

  • Use keywords for parameters that have meaningful and stable names.
  • Use keyword-only for options and booleans
  • Use positional-only where parameter names would have little to no meaning or where you might want to change parameter names later.
  • Annotate to give callers with an explicit recipe for your API.

Types of parameters

  1. Positional-or-Keyword: By default, Python parameters can be passed by position or by name. For def my_func(param1: str, param2: str, param3: list):, Python first binds any argument with explicit keywords to its corresponding parameter, then binds any remaining positional arguments in order. These calls are equivalent:
    my_func('a', 'b', [1, 2, 3])
    my_func(param3=[1, 2, 3], param2='b', param1='a')
    my_func('a', param2='b', param3=[1, 2, 3])

    Note: Positional arguments must come before keyword args. my_func(param2='b', param1='a', [1, 2, 3]) is invalid.

  2. Positional-Only: Parameters before a / in the signature are positional-only PEP 570. Use when a name adds little to no meaning, or when you want freedom to rename later. Examples:
    sorted(iterable, /, *, key=None, reverse=False)iterable is positional-only.
    pow(x, y, z=None, /) → all three are positional-only.

  3. Keyword-Only: Parameters after a bare * must be passed by name (PEP 3102. Great for optional parameters and booleans because they enforce self-documenting call sites.

  4. Optional: A parameter becomes optional when you give it a default. When omitted at the call site, an optional parameter will be assigned the default value, which should correspond to expected behavior. Examples: reverse=False in sorted(); ascending=True in pandas.DataFrame.sort_values(); startrow = 0 in pandas.DataFrame.to_excel().

  5. Variable Length Arguments: Var-positional (*args) collects extra positional values; Var-keyword (**kwargs) collects extra named options. Often used to forward to another API. Rules of thumb
    -Prefer explicit parameters when you can.
    -Use *args/**kwargs when you truly need "any number of" values/options or you're writing wrappers.

Annotations

Annotations provide users with explicit clues about which types are expected for any parameter, and which types a function will return. The syntax is name: Type for parameters and -> Type for the return. They're hints, not runtime enforcement.

Example:
def get_one_path(data_dir: Path, ptrn: str, *, ext: str | None = None) -> Path:

  • data_dir: Path → expects a path-like object.
  • ptrn: str → expects a string object.
  • ext: str | None = None → optional keyword-only; expects a string or None; defaults to None.
  • -> Path → the function returns a Path.

tags: #Python, #tools-and-languages, #instructive

The Python Parameters Playbook