f-strings don't behave nicely when used with dictionaries, as mentioned here.
Here is an example of the not-so-nice behavior:
d = {'foo': 'bar'}
# Both work as expected
d["foo"]
d['foo']
# This only works when different quotations are used in the inner and outer strings
f'{d["foo"]}'
f"{d['foo']}"
# This doesn't work
f'{d['foo']}'
f"{d["foo"]}"
# The .format() method doesn't care
'{}'.format(d['foo'])
The last two f-strings listed result in a SyntaxError: invalid syntax
, which happens because the string '{d['foo']}'
is evaluated as '{d['
foo']}'
.
What is the underlying reason everything inside the curly brackets of f-strings doesn't get evaluated separately, as when using the old .format()
method, and what could possibly be the reason for implementing f-strings in this way?
I love f-strings, but this seems like a point in favor of the old method.
F-strings are literal strings. Including unescaped quotes within quotes (of the same type) is invalid syntax. This makes sense, since the result is ambiguous: the interpreter will not know when the string should end. One traditional way of including quotes within quotes is to use a backslash. But PEP498 forbids backslashes in expressions within f-strings:
Backslashes may not appear inside the expression portions of f-strings...You can use a different type of quote inside the expression...
Therefore, the only way left to access a dictionary value given a key in an f-string expression is to use a different type quote. Using single quotes, or double quotes, everywhere is ambiguous and gives SyntaxError
.
str.format
is a regular method, and as such works differently: d['foo']
is evaluated before the string is constructed. Just like when you feed arguments to a function, the arguments are evaluated before the function does anything.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With