[KongchangAI]
· 2 min read· 1,315 words

Writing Python Docstrings with AI: A Practical Guide to Prompts That Actually Work

Writing Python Docstrings with AI: A Practical Guide to Prompts That Actually Work

Concrete input-output examples in prompts boost AI-generated Python docstring quality from 30% to 85% usable.

A developer tried using AI to batch-generate docstrings for a Python utility repository, only to find that simple prompts produced technically correct but useless output — just the function name rephrased. Even GPT-4 struggled without sufficient context, making productivity go negative. The breakthrough came from treating AI like a junior dev: providing concrete input-output example pairs (similar to unit tests) in the prompt. This jumped quality from ~30% to ~85% usable, yielding precise descriptions, executable examples, and edge case coverage. The core lesson: example-driven prompting constrains model behavior far better than abstract adjectives, but AI remains a copilot — complex functions still need human review.

What's it like to maintain a Python repository stuffed with utility functions? Small, frequently used snippets written on the fly over months, with almost no documentation. Then one day you find yourself staring blankly at process_complex_csv_data(filepath, schema_config, output_dir), unable to remember what it actually does — so you dive back into the function body and read it all over again. Naturally, your mind turns to large language models: let AI batch-generate docstrings and save yourself hours of grunt work. Sounds too good to be true.

In practice, it's far more complicated than it sounds. One developer shared his full experience wrestling with AI — going from generating piles of "technically correct but useless" documentation to finally finding an effective prompting strategy. The core takeaway is straightforward: AI is not a magic documentation generator. The quality of its output depends entirely on the instructions and context you feed it.

Why Just Pasting Code Fails

The initial approach was intuitive enough: grab a function, paste it into the OpenAI playground or call gpt-3.5-turbo directly, with a simple prompt — "Generate a Google-style docstring for the following Python function."

Take this string normalization function as an example:

import re

def normalize_string_for_search(text: str, lower_case: bool = True, strip_punct: bool = True) -> str:
    if lower_case:
        text = text.lower()
    if strip_punct:
        text = re.sub(r'[^\w\s]', '', text)
    return text

A typical result from gpt-3.5-turbo looked like this:

"""
Normalizes a string for search purposes.

Args:
    text (str): The input string to normalize.
    lower_case (bool, optional): Whether to convert the string to lowercase. Defaults to True.
    strip_punct (bool, optional): Whether to strip punctuation from the string. Defaults to True.

Returns:
    str: The normalized string.
"""

What's wrong with it? It's not incorrect, but it's nearly useless. "Normalizes a string for search purposes" is just the function name rephrased. It doesn't tell you how it normalizes — which punctuation gets stripped? What do you get if you pass in "Hello, World!" with default parameters? No usage examples, no edge case coverage — pure filler. The author described it as the documentation equivalent of "this function processes data" — thanks, Captain Obvious.

Practical experience generating Python docstrings with AI

Worse still was the return on investment. The author spent a total of four hours trying various tweaks: "Be more specific!" "Add examples!" "Think like a human!" Results ranged from marginally better to equally mediocre. Even switching to GPT-4 with the same simple prompt — while smarter — still struggled to infer the function's intent and impact, staying stuck at the surface of the code. At one point his productivity turned negative — reviewing and fixing the generated docstrings took more effort than writing them from scratch.

The Google-style docstring is one of the most widely adopted Python documentation conventions, popularized by Google in its Python Style Guide. Its structure includes a one-line summary, an optional extended description, and indented sections for Args:, Returns:, Raises:, and Examples:. Compared to NumPy style (which uses dashes to separate sections) and reStructuredText style (which uses :param: prefixes), Google style offers strong readability and clear visual hierarchy — making it widely supported by tools like Sphinx and countless open-source projects. Understanding the specific requirements of this convention helps you see exactly where AI-generated docstrings fall short — not just in content, but sometimes in format, causing documentation tools to fail when parsing them.

What Actually Works: Give AI "Unit Tests"

The turning point came when the author realized he'd been treating AI as a magic black box that could infer context on its own. It can't — at least not fully. You have to explicitly tell it what to look for and what purpose the documentation serves. The key insight: it needs examples, not just instructions.

The effective strategy was to give AI richer context, treating it like a junior developer who needs to understand the "why" and "how" — not just the "what." Using the gpt-4-0125-preview model, the prompt structure looked roughly like this:

You are a senior Python developer responsible for writing complete Google-style docstrings.
The documentation should explain what the function does, its parameters, return values, 
and include at least two clear, distinct usage examples — covering edge cases where applicable.

Here is the Python function:

[function code]

Examples of expected behavior:
1. Input text="Hello, World!", lower_case=True, strip_punct=True -> Output "hello world"
2. Input text="AI & ML rocks!", lower_case=False, strip_punct=True -> Output "AI ML rocks"
3. Input text="What's up, Doc?", lower_case=True, strip_punct=False -> Output "what's up, doc?"

Now generate a complete Google-style docstring for the function above, incorporating these examples.

The results were immediate. By providing concrete inputs with expected outputs, the author was essentially teaching the model the function's behavior in a way it could actually understand — like writing unit tests for documentation. Quality jumped from "roughly 30% usable" to "about 85% usable."

The improved docstring looked like this:

"""
Normalizes a string for search queries by optionally converting it to lowercase and stripping punctuation.

Args:
    text (str): The input string to be normalized.
    lower_case (bool, optional): If True, converts the string to lowercase. Defaults to True.
    strip_punct (bool, optional): If True, removes all punctuation characters (non-alphanumeric, non-whitespace). Defaults to True.

Returns:
    str: The normalized string suitable for search.

Examples:
    >>> normalize_string_for_search("Hello, World!", lower_case=True, strip_punct=True)
    'hello world'
    >>> normalize_string_for_search("AI & ML rocks!", lower_case=False, strip_punct=True)
    'AI ML rocks'
    >>> normalize_string_for_search("What's up, Doc?", lower_case=True, strip_punct=False)
    "what's up, doc?"
"""

The description became more precise ("non-alphanumeric, non-whitespace characters"), and it included real >>> executable examples that make usage immediately clear. It understood the "search purposes" context because the author explicitly told it.

Prompt Engineering refers to the methodology of carefully crafting input text to guide large language models toward producing target-quality outputs. "Few-shot Prompting" is one of its core techniques: by including several input-output example pairs directly in the prompt, you let the model "read" the task specification from examples rather than relying on abstract descriptions. This differs from traditional machine learning fine-tuning — it doesn't modify model weights, but instead constrains the output distribution at inference time through context. The author's effective strategy is essentially an application of few-shot prompting: three concrete input-output pairs serve as implicit specifications, anchoring the vague concept of "normalization" to verifiable behavior, rather than letting the model free-associate based on statistical tendencies in its training data.

The Key Lesson: AI Is Copilot, Not Autopilot

The greatest value of this case study is revealing a widely overlooked principle of prompt engineering: concrete input-output examples constrain model behavior far more effectively than abstract adjectives. When you ask AI to be "more specific" or "more useful," those words carry almost no actionable information for the model. Three real input-output pairs, on the other hand, directly show it what "success" looks like.

This also explains why simply upgrading to GPT-4 doesn't solve the problem. Improved model capability cannot compensate for missing context — the intent behind a function often isn't written in the code at all; it lives in the developer's head. If you don't articulate it, even the most powerful model can only guess.

From a workflow perspective, this approach has a cost-benefit ratio worth considering. It requires upfront effort to work out your prompting strategy and write a few key examples for each function — but once the pattern is established, you can move relatively quickly through that backlog of undocumented utility functions: write a few examples, feed them to AI along with the function, and get a solid first draft.

It's not fully automated — complex functions still need human fine-tuning — but it genuinely works as a "documentation copilot." For repositories long burdened by documentation debt, this is a pragmatic path to paying it down. The real takeaway: if you want gold from AI rather than generic filler, you have to show it — concretely — what gold looks like.

#Python docstring#AI documentation generation#prompt engineering#few-shot prompting#GPT-4#Google-style docstring#LLM code documentation
Share:

Related articles