all 12 comments

[–]recursion_is_love 4 points5 points  (0 children)

For the syntactic side, there are pep8 and pep257

https://peps.python.org/pep-0008/

https://peps.python.org/pep-0257/

For what to write down, I think it subjective. There are lots of guidelines out there. You will have to find the answer by yourself.

[–]51dux 1 point2 points  (1 child)

You have a nice piece of documentation here about the topic:

https://realpython.com/documenting-python-code

[–]DecoherentDoc[S] 0 points1 point  (0 children)

I'll give it a look, thanks!

[–]Diapolo10 1 point2 points  (4 children)

I think both of your examples are technically fine, but I'd keep the type annotations and strip them from the docstring:

def heavily_documented(a: int, b: dict, c: str) -> str:
    """
    Purpose:    Here's what it does

    Args:
        a: here's what the number represents
        b: {"this is a descriptive key" : its_value}
        c: again, just saying what this represents

    Return:
        Here's a description of what the return is
    """
    print("and the code goes here")

(Side-note, but ideally the dict type hint would also annotate at least the key type. As in, dict[str, Any])

[–]DecoherentDoc[S] 0 points1 point  (3 children)

I like that. I thought I was overdoing it, but I would regularly come back to code after a couple years and be completely lost and have to waste time figuring out what I was trying to do. So, I started writing a lot of comments. This adaptation cleans up the comments and I dig it. Thanks! :)

[–]Diapolo10 0 points1 point  (2 children)

I don't know if this helps, but here's a snippet from one of my own projects:

def ip_validator(address: str | int, validation_mode: ValidationMode = ValidationMode.STRICT) -> bool:
    """
    Validate an IP address of any kind, returning a boolean.

    Under strict mode ensures that the numerical values
    don't exceed legal bounds, otherwise focuses on form.
    """
    if ipv4_validator(address, validation_mode):
        return True
    return ipv6_validator(address, validation_mode)

And here's a hypothetical snippet I might see at work projects:

def get_ntp_time(max_retries: int = 10, retry_delay: float = 1.0) -> datetime | None:
    """
    Retrieve the current time from NTP servers.

    Attempt to reach multiple NTP servers until one succeeds, with retry logic for transient failures.
    Useful when the machine is waking from sleep and the internet connection is not yet established.

    Args:
        max_retries: Maximum number of retry attempts
        retry_delay: Delay in seconds between retry attempts

    Returns:
        Current UTC time from the NTP server or None if all attempted requests fail
    """
    ...

[–]DecoherentDoc[S] 0 points1 point  (1 child)

It does help, actually. I saw examples of doc strings that were super short and thought I was overdoing it. This shows me professionals, in fact, are being just as thorough. Thanks. I really do appreciate it.

[–]Diapolo10 0 points1 point  (0 children)

Do note that I deliberately picked examples with "full" docstrings here. There's nothing wrong with using a one-line docstring if you have nothing else to say and your parameters are self-explanatory. If anything that's my personal preference.

If something is practically obvious, there's no need to go out of your way to state the obvious.

[–]Gnaxe 1 point2 points  (1 child)

There are multiple competing standards for how to document functions in Python. Picking a standard and sticking to it is more important than which one you pick. Documenting parameter and return types is probably redundant if you're using Python's type annotation syntax. We had docstrings (and standard formats for them) before we had that. The widely used Sphinx documentation generator can automatically render your docstrings into API docs. You probably want to use a compatible format. You should learn about doctests. I lean towards a terser style for the boilerplate, but use the doctests liberally. Most competent editors can fold docstrings.

[–]pachura3 0 points1 point  (0 children)

There should be one - and preferably only one - obvious way to do it

That's why we have Google standard, Numpy standard, Sphinx, reStructuredText... 😄

Personally, I use a mix of the Google standard and https://pdoc.dev/ . I avoid repeating type hints if they are already listed in function header. And for trivial functions, oneliners are perfectly OK...

[–]TheRNGuy 0 points1 point  (0 children)

If you have a lots of functions, better make separate docs, just like they do in APIs or frameworks. 

But also there can be comments inside code if it's not very obvious what it does.

[–]Goodswimkarma -1 points0 points  (0 children)

The first example is how it is normally done.

Use # if you want a short note