5

When I'm creating a docstring, sometimes I want to refer to a value, for instance:

def try_download(data, path):
    """Tries to download ATTEMPTS times, catching socket errors."""

Where ATTEMPTS is just a constant int defined at the start of the file. But would it be better to write it so that it's generating a string actually indicating what the value is, ie.

def try_download(data, path):
    """Tries to download {} times, catching socket errors.""".format(ATTEMPTS)

The advantage to this, would be that someone else reading dynamically from the function would get a more helpful message indicating the actual number. However someone reading the actual script has a slightly less readable sentence. There's also a degree of danger that this makes the docstring error prone in that errors could occur, but in reality if it's replaced by a number that can't be printed, the actual function will have bigger problems than it's docstring.

So is this worrying over nothing, or is it better to stay safe and not insert variables into docstrings?

  • Is this a comment, or is it actually executed? If it's a comment, use the first version. If it's actually executed, use the second version. – Robert Harvey Aug 4 '16 at 17:18
  • 3
    As an aside, does this actually work? In Common Lisp (which also has docstrings), checking whether something is a docstring or not requires checking whether (i) it's a string, (ii) it's at the beginning of a body (it's actually a bit more complex, but that's not the point here), and (iii) it's not the last thing in the body (in which case it would be the return value, not the docstring). The first expression in your function body isn't a string; it's a function call. Does Python check to see whether the first expression would evaluate to a string and then... – Joshua Taylor Aug 4 '16 at 21:56
  • ..decide to evaluate it and use it as a docstring if it does? How would it know whether that first expression would be a string or not? E.g., compare def foo(): bar(1) where bar returns a string if the argument is 1 and a number if the argument is 2. Is Python supposed to figure out that bar(1) will return a string, and thus that value should be used as a docstring? What should happen if you do: def try_download(attempts): """Attempt a download {} times.""".format(attempts)? I don't see how that could be treated as a docstring. – Joshua Taylor Aug 4 '16 at 21:59
6

The approach you're describing doesn't actually produce a docstring. It doesn't result in the __doc__ property of the function being set, which means that it's not available to the help function, and wouldn't be available to (typical) automated documentation generators. Here's a simple example that shows this in action. First, a function with a "traditional" docstring:

>>> def bar():
    "some value: 42"
    return 42

>>> bar.__doc__
'some value: 42'

>>> help(bar)
Help on function bar in module __main__:

bar()
    some value: 42

Note that the __doc__ property is set, and help will show the contents of that string. Now, let's try with the dynamically generated "docstring". I put docstring in scare quotes because it's not actually a docstring.

>>> def foo():
    "some value: {}".format(3)
    return 42

>>> foo.__doc__

>>> help(foo)
Help on function foo in module __main__:

foo()

There's no value for foo.__doc__, and help doesn't display anything aside from the function declaration, which means that the system didn't interpret the value as a docstring. That's not really surprising, since the first expression in the function body isn't a string, it's a function call to a member function of a string.

So, to answer the questions,

Is it poor practice to have dynamically updated docstrings?

There are ways to dynamically update a docstring, viz., by setting the __doc__ property of the function, but that's not what your approach is doing. Whether it's good or bad practice probably depends on the application. If you're dynamically generating some functions and want to programatically assign documentation to them, it might be fine. In the way that you're describing though, it simply doesn't work.

The advantage to this, would be that someone else reading dynamically from the function would get a more helpful message indicating the actual number.

It depends on what you mean by "reading dynamically from the function". It might be helpful to someone reading the source, but it's definitely not helpful to someone who is looking at the output of help, or who is reading the value of the __doc__ property.

| improve this answer | |
2

In my opinion such use of docstrings would be unexpected. Docstrings are used to explain what does an object, explain its parameters or propose usage of the object.
In your case you are saying something about the execution of your function, not how does it works so I wouldn't create it dynamically. If this is set on the begining of the file then it may be needed as a parameter and you could explain that such parameter controls how many times the download is tried. As you noted it could introduce a new source of errors in the documentation! It is better to keep the documentation clear and to the point.

| improve this answer | |
  • It should be noted that this doesn't actually produce a dostring, i.e., a value that is stored as function.__doc__. That means that for programmatic access of documentation, this approach doesn't work at all. The "docstring" ends up being just another expression that is evaluated in the execution of the function. – Joshua Taylor Aug 5 '16 at 13:46
  • Thanks for your answer! I didn't remember docstrings was stored in foo.__doc__ – llrs Aug 5 '16 at 15:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.