You describe f-strings as “literals” in the PEP. Please don’t do that. F-strings can contain executable code and can have side-effects. They are code not string literals.
We don’t talk about “def
literals” and “lambda
literals”. The documentation doesn’t even refer to list or dict literals (rather, “displays”). We shouldn’t abuse the word literal to describe f-strings either.
The PEP says:
(emphasis added) and then give three examples:
f"These are the things: {", ".join(things)}"
f"{source.removesuffix(".py")}.c: $(srcdir)/{source}"
f"{f"{f"infinite"}"}" + " " + f"{f"nesting!!!"}"
The first two might be perfectly understandable to the parser, but as a human reader, they make it more complicated and error-prone to work out which quotes delimit the f-string and which do not.
Especially when the f-string may be concatenated with other strings, or embedded in larger expressions. Even more especially when used with long line lengths.
Taken in isolation, the human reader can just look at the start of the line and see the f"
token, and then skip to the end of the line to find the matching close quote. But in real code, where f-strings are often embedded in complex expressions and long lines, it is not that easy. You have to manually parse the f-string, counting quotes and braces, and work out which ones are paired with which other ones.
You know. The sort of thing computers are excellent at but people suck at.
I consider the first two examples terrible code which should be discouraged and the fact that your PEP allows it is a point against it, not in favour.
Especially since we can get the same effect by just changing one of the pairs of quotes to '
. So in this regard, the PEP doesn’t even add functionality. It just encourages people to write code which is harder to read and more error prone.
In Python 1.x and 2.x, we had the backtick for evaluating the repr of objects. It could be nested exactly as you have here:
# Python 2.7
>>> `(`123`, 456)`
"('123', 456)"
One of the reasons we got rid of it was because it was too hard for the human reader to read nested backtick expressions.
Also keep in mind that many editors will have very simple-minded colourizers. Code inside f-strings may not be colourized, or if it is, the colourizer surely won’t include a full blown Python parser. So it will likely colour the first example as a comma-separated pair of strings:
f"These are the things: {" COMMA ".join(things)}"
and the second looks like you are calling a .py
method on a string literal, followed by a quote instead of the opening paren. Many editors will colour this as a syntax error, or at least least, incorrectly.
f"{source.removesuffix(" .py ")}.c: $(srcdir)/{source}"