1
def foo():
    ("abc"
     "def")

def bar():
    ("abc"
    f"def")

The function foo got a docstring but bar's doc is null.

>>> bar.__doc__
>>> foo.__doc__
'abcdef'

Why does the f-string prevent the function from taking a __doc__ attribute?

Woodford
  • 3,746
  • 1
  • 15
  • 29
no step on snek
  • 324
  • 1
  • 15
  • Does this answer your question? [Can a Python docstring be calculated (f-string or %-expression)?](https://stackoverflow.com/questions/70863543/can-a-python-docstring-be-calculated-f-string-or-expression) – Woodford Jul 11 '23 at 17:20
  • @Woodford No. This code is not attempting to format the string. – no step on snek Jul 12 '23 at 01:00

2 Answers2

4

Docstrings need to be attached to the function at definition time, but an f-string inside the body of the function would normally need to be evaluated later, during the function call, in order to do interpolation. Since figuring out a sensible way for this to work is hard, f-strings simply aren’t eligible to be considered docstrings; only static string literals are.

https://github.com/python/cpython/issues/72925

Samwise
  • 68,105
  • 3
  • 30
  • 44
  • does my answer count as a work-around? – Ori Yarden PhD Jul 11 '23 at 20:18
  • @OriYardenPhD One issue with your workaround is that the docstring isn't created until you *call* the function; you'd rather have it be defined as soon as possible after *defining* the function. – chepner Jul 11 '23 at 20:46
  • But it is already known at function definition time whether or not the f-string has any expressions which will need to be evaluated (that's part of the parser's job) – no step on snek Jul 11 '23 at 21:05
  • "Docstrings can be f-strings as long as they don't contain anything that makes the fact that they're f-strings relevant" is a more confusing rule IMO then "f-strings are never docstrings". Python generally leans toward having rules that are simple to understand. – Samwise Jul 11 '23 at 21:52
  • 1
    Ah, Guido says more or less exactly that in the bug discussion, heh: https://github.com/python/cpython/issues/72925#issuecomment-1093732356 It looks like it actually used to work the way you describe where f-strings were considered to be regular string literals as long as they didn't have curly braces, and confusion over why they worked sometimes and not others is why it was changed so that they just never work. – Samwise Jul 11 '23 at 21:56
  • Fair enough. I guess this is "Special cases aren't special enough to break the rules" – no step on snek Jul 12 '23 at 00:59
2

If you want a computed docstring, do so after the function is defined. It's a syntactic convenience that the function's __doc__ attribute is set to the first string literal found in the body of a def statement. You can always set it manually once the function has been defined.

def bar():
    pass

bar.__doc__ = "abc"f"def"

One way to "automate" this is to define a decorator that sets __doc__ from an argument.

def set_docstring(s):
    def _(f):
        f.__doc__ = s
        return f
    return _


@set_docstring("abc"f"def")
def foo():
    pass

Since Python 3.9, you can define the decorator inline (though it's not exactly pretty):

@lambda f: setattr(f, '__doc__', "abc"f"def") or f
def foo():
    pass
chepner
  • 497,756
  • 71
  • 530
  • 681