Why can not f-strings be used as a docstring?

8

According to PEP 257 , you have:

  

A docstring is the literal string that occurs as the first statement in a module, function, class, or method definition. Such a docstring becomes the __doc__ special attribute of that object.

That is, the docstring is a literal string that is the first statement of a module, class, or function, which will be accessible by the%

def hello():
    'Exibe uma saudação'
    print('Hello')

print(hello.__doc__)  # Exibe uma saudação

See working at Repl.it | GitHub GIST

But if we try to use a f-string , with formatting , the value of __doc__ will be __doc__ .

__author__ = 'Anderson Carlos Woss'

def hello():
    f'Autor: {__author__}'
    print('Hello')

print(hello.__doc__)  # None

See working at Repl.it | GitHub GIST

    
asked by anonymous 17.08.2018 / 20:00

2 answers

4

Because f-string ceases to be literal, by definition, it becomes a candidate to be docstring .

Also because the docstring is generated at compile time, when the byte-code is generated it will be interpreted - as Maniero comments on response , this was a design choice; they could make the value be evaluated at runtime, but they saw no reason to do so. So, how to guarantee the value of the objects that will be interpolated? In the case of the question, the interpolation occurs only with a global variable and could generate the docstring "Author: Anderson Carlos Woss", but what if I do at some other point in the __author__ = 'Foo' code, this should to change the docstring ? This worsens if we consider that we could add the value of a function parameter in docstring :

def hello(name):
    f'Saudação para {name}'
    print(f'Hello, {name}')

In this case, what would be the value of hello.__doc__ ? One option would be to consider the string as docstring , but again, this was a design choice. What would a docstring sense with the value Autor: {__author__} ?

As for not being a literal string, see the difference between the opcodes generated for a normal string and an f -string .

Normal String

>>> print(dis.dis('"Hello"'))
  1           0 LOAD_CONST               0 ('Hello')
              2 RETURN_VALUE
None

F-String

>>> print(dis.dis('f"Hello {name}"'))
  1           0 LOAD_CONST               0 ('Hello ')
              2 LOAD_NAME                0 (name)
              4 FORMAT_VALUE             0
              6 BUILD_STRING             2
              8 RETURN_VALUE
None

The extra steps to format and construct the final string make f-string no longer just a literal value and need this execution. For example, see the opcode generated when a string literal is used as docstring :

  2           0 LOAD_CONST               0 ('Hello world')
              2 STORE_NAME               0 (__doc__)

  3           4 LOAD_NAME                1 (print)
              6 LOAD_CONST               1 ('Hello')
              8 CALL_FUNCTION            1
             10 POP_TOP
             12 LOAD_CONST               2 (None)
             14 RETURN_VALUE
None

Notice that it stores the string within the __doc__ object, be it the module, class, or function. However, when reporting a f-string , the result is:

  2           0 LOAD_CONST               0 ('Hello ')
              2 LOAD_NAME                0 (name)
              4 FORMAT_VALUE             0
              6 BUILD_STRING             2
              8 POP_TOP

  3          10 LOAD_NAME                1 (print)
             12 LOAD_CONST               1 ('Hello')
             14 CALL_FUNCTION            1
             16 POP_TOP
             18 LOAD_CONST               2 (None)
             20 RETURN_VALUE
None

That is, the interpreter will evaluate the f-string , interpolate the values and return the string end, which will no longer be a docstring will be a unique string in the code and therefore discarded. As a literal string is not reported, the function ends up without a docstring , so it returns None .

    
17.08.2018 / 21:11
3
The docstring mechanism should be very simple, just have a constant value that gets stored somewhere and if invoked it is brought up because who needed it. It was not the language's intention to provide a more sophisticated mechanism. The f-string is more sophisticated, it has code execution to arrive at a result because the interpolation does not occur magically just because the syntax seems to indicate this, there is the call of a function that properly concatenates the necessary texts.

This can be confirmed when you have opened a bug in documentation that has been accepted to indicate that you can not even.

They might have opted to make a more sophisticated mechanism that would allow them to be solved at runtime, nor would it be much outside the philosophy of language, but in general does not compensate, I even question the necessity of this type of thing in the current form, the language already has a more sophisticated way of doing this, although it requires more effort. And even to do just this manually is quite simple.

    
17.08.2018 / 20:25