0%

More Expressive Functions · practice

Make Important Arguments Explicit

The previous lesson showed that keyword can make a call easier to read. We chose to write status="needs review" instead of supplying one more unexplained .

However, keyword arguments were only a choice. Python would still accept the positional version. For some settings, we would rather require the names.

Consider a function that can clean a response in two different ways:

def normalize_response(
    response,
    ignore_case=False,
    trim_spaces=True,
):
    ...

Without looking back at the definition, try to read this call:

normalize_response("  Python  ", True, False)

The two values do not explain themselves. Does True mean “ignore letter case” or “trim spaces”? To answer, a reader must find the function definition and carefully match each position.

Require the setting names

Python lets us place * before the settings in the function definition:

def normalize_response(
    response,
    *,
    ignore_case=False,
    trim_spaces=True,
):
    ...

The * divides the into two groups:

  • response comes before *, so it may still be supplied by position.

  • ignore_case and trim_spaces come after *, so their names are required.

Parameters whose names are required are called keyword-only parameters. The readable call is now the only valid form:

normalize_response(
    "  KEEP CASE  ",
    ignore_case=False,
    trim_spaces=True,
)

The * does not receive a . It only changes how later arguments must be supplied. The function body can continue using ignore_case and trim_spaces as ordinary Boolean values.

Passing a keyword-only setting by position raises before the function body runs.

Use this rule when the names add clarity

Requiring names is especially helpful for:

  • Boolean switches;

  • several settings that use the same type of value;

  • optional choices that noticeably change what a function does.

Not every argument needs this rule. A short call such as round(3.14159, 2) is already familiar and compact. Keyword-only parameters help when the added names make a call meaningfully easier to understand.

What happens when the final line runs?

def clean(text, *, lowercase=False):
    if lowercase:
        return text.lower()
    return text


print(clean("Python", True))

The valid call is clean("Python", lowercase=True).

Repair an invalid call

The function in the editor is already complete, but the code that calls it supplies both settings by position. Run the starter code and read the TypeError. Then repair the call by naming the two keyword-only arguments. The printed | characters make any spaces that remain visible.

Keep the * in the function definition. Removing it would hide the mistake instead of fixing the unclear call.

Task

Run the starter code and inspect its . Then repair the call that creates result.

  • Keep response as the positional .

  • Supply ignore_case=True by keyword.

  • Supply trim_spaces=False by keyword.

  • Keep the *, the body, and the final print unchanged.

The repaired program should print | python |. The bars are only boundaries; the two spaces on each side of python are part of result.