Why does Python care about Contents in Comments?

I’m new to Python, and I’ve run into an issue where two things work against each other, and I wonder why this is an issue for Python at all:

I document my code with Doxygen (yes, I know that python has it’s own standard for that, but we doc every language in Doxygen here). In one of the multiline comments I use to document a function, I use a percent sign (‘%’). For Doxygen I have to escape this as backslash+percent sign (‘\%’).

With that, Doxygen runs fine, but Python complains about “SyntaxWarning: invalid escape sequence ‘\%’”.

Why does Python care about the way I’m escaping things in a comment? I could understand about complaining about an escape sequence for double quote signs (‘“‘), as this might influence finding the end of the multiline comment, but complaining about a percent sign?

Furthermore, if I interpret the search results correctly, this is a warning ahead of making this kind of escaping illegal, AKA turning this into an error. Now that would put me into a bind…

What is the correct way to make both worlds happy?

There is a difference between “multi-line strings” and “comments”. It sounds like you’re trying to put the invalid escape sequence in a string.

def f():
  """this
  is
  a
  string
  """
  #these
  #are
  #comments

The fix you’re looking for is probably to use r-strings for your docstrings.

def f():
  r"""This \% is
  fine with python \%
  """
1 Like

Thank you for your reply.

So the triple double quote thing is not a comment, despite everyone using it as such, even in loads of examples on the net. Wonderful…

If it is considered a string, I could do

Mystring=”””

something

even more

last line

“““

and it would assign a string with line breaks then? And when “abused” as a multiline comment, it is just ignored because it’s not assigned to anything?

What is that lowercase r-triple double quote thing officially called, or under which keyword can I find it in the docs?

Yeah, a lot of people treat it as a comment, but it really isn’t one.

Exactly. That isn’t an abuse, per se; there are actually a LOT of places in Python where we calculate something and then throw it away. For example, some_list.pop() returns the popped element, but if you don’t care what it is, you can just call it and discard the result. [1] And there are quite a few idioms that involve discarding a value because it’s not interesting:

def do_stuff():
    ...

Technically this is the expression Ellipsis and it discards that, but it’s a very common idiom, used when we have a function that still needs to be implemented.

So, I wouldn’t say it’s inherently an abuse to use a string literal when you don’t actually want to use it. However, you do have to know that this is not a comment.


  1. Technically this happens with ALL function calls - even print("Hello, world") has a return value, just an uninteresting one. ↩︎

1 Like

Yep and all those people are wrong. It is a string literal. String literals are evaluated.

Many editors/IDEs make it easy to change a selection of lines into multiple commented lines, and linters can complain about these bare string literals, but:

  • Docstrings need to be strings, and they are documentation which is close to comments right? (Wrong).
  • Gosh, it’s so easy… :slightly_smiling_face:

It has to be evaluated, because it is assigned to func.__doc__:

def f():
    "Hello world!"
print(f.__doc__)

It is a string used for documentation. Because Python is often used interactively, this can actually be useful.

r-strings are r-strings. Triple quoted strings are multiline strings. You can have a string that’s both an r-string and a multiline string. I doubt this particular combination has a specific name, or specific docs. It just has the properties of both r-strings and multiline-strings.

1 Like

A string with the rprefix is called a “raw” string.

def do_stuff():
    ...

This works? Amazing…

1 Like

TIL. This is crazy. In a positive way. Thank you!

1 Like

Thanks, found it!

Additionally, language servers like pyright will allow you to document attributes using string literals:

class A:
    """This is class A""" # Shows up in A.__doc__
    my_attribute: str
    """This is a string attribute""" # Discarded at runtime, but is still parsed

If you’re using an editor that has a Python language server available, you should now see that docstring show up when you access A.my_attribute or A().my_attribute.

I don’t believe that this doc is carried along with the object at runtime though, it’s just for linting purposes.

Edit: Here’s that in action with pyright