Disallow backslashes in the expression part of f-strings. See https://mail.python.org/pipermail/python-dev/2016-September/146357.html for a discussion and an implied acceptance by Guido.

This commit is contained in:
Eric V. Smith 2016-11-06 11:18:17 -05:00
parent b60019e09a
commit ac0afc6434
1 changed files with 36 additions and 43 deletions

View File

@ -171,9 +171,9 @@ Specification
In source code, f-strings are string literals that are prefixed by the
letter 'f' or 'F'. Everywhere this PEP uses 'f', 'F' may also be
used. 'f' may be combined with 'r', in either order, to produce raw
f-string literals. 'f' may not be combined with 'b': this PEP does not
propose to add binary f-strings. 'f' may not be combined with 'u'.
used. 'f' may be combined with 'r' or 'R', in either order, to produce
raw f-string literals. 'f' may not be combined with 'b': this PEP does
not propose to add binary f-strings. 'f' may not be combined with 'u'.
When tokenizing source files, f-strings use the same rules as normal
strings, raw strings, binary strings, and triple quoted strings. That
@ -183,33 +183,24 @@ This implies that any code that currently scans Python code looking
for strings should be trivially modifiable to recognize f-strings
(parsing within an f-string is another matter, of course).
Once tokenized, f-strings are decoded. This will convert backslash
escapes such as ``'\n'``, ``'\"'``, ``"\'"``, ``'\xhh'``,
``'\uxxxx'``, ``'\Uxxxxxxxx'``, and named unicode characters
``'\N{name}'`` into their associated Unicode characters [#]_.
Up to this point, the processing of f-strings and normal strings is
exactly the same.
The difference is that f-strings are further parsed in to literals and
expressions. Expressions appear within curly braces ``'{'`` and
``'}'``. The parts of the string outside of braces are literals. The
expressions are evaluated, formatted with the existing __format__
protocol, then the results are concatenated together with the string
literals. While scanning the string for expressions, any doubled
Once tokenized, f-strings are parsed in to literal strings and
expressions. Expressions appear within curly braces ``'{'`` and
``'}'``. While scanning the string for expressions, any doubled
braces ``'{{'`` or ``'}}'`` inside literal portions of an f-string are
replaced by the corresponding single brace. Doubled opening braces do
replaced by the corresponding single brace. Doubled opening braces do
not signify the start of an expression.
Note that ``__format__()`` is not called directly on each value. The
actual code uses the equivalent of ``type(value).__format__(value,
format_spec)``, or ``format(value, format_spec)``. See the
documentation of the builtin ``format()`` function for more details.
The parts of the f-string outside of braces are literal
strings. These literal portions are then decoded. For non-raw
f-strings, this includes converting backslash escapes such as
``'\n'``, ``'\"'``, ``"\'"``, ``'\xhh'``, ``'\uxxxx'``,
``'\Uxxxxxxxx'``, and named unicode characters ``'\N{name}'`` into
their associated Unicode characters [#]_.
Comments, using the ``'#'`` character, are not allowed inside an
expression.
Backslashes may not appear anywhere within expressions. Comments,
using the ``'#'`` character, are not allowed inside an expression.
Following the expression, an optional type conversion may be
Following each expression, an optional type conversion may be
specified. The allowed conversions are ``'!s'``, ``'!r'``, or
``'!a'``. These are treated the same as in ``str.format()``: ``'!s'``
calls ``str()`` on the expression, ``'!r'`` calls ``repr()`` on the
@ -231,6 +222,11 @@ The expression is then formatted using the ``__format__`` protocol,
using the format specifier as an argument. The resulting value is
used when building the value of the f-string.
Note that ``__format__()`` is not called directly on each value. The
actual code uses the equivalent of ``type(value).__format__(value,
format_spec)``, or ``format(value, format_spec)``. See the
documentation of the builtin ``format()`` function for more details.
Expressions cannot contain ``':'`` or ``'!'`` outside of strings or
parentheses, brackets, or braces. The exception is that the ``'!='``
operator is allowed as a special case.
@ -238,21 +234,21 @@ operator is allowed as a special case.
Escape sequences
----------------
Scanning an f-string for expressions happens after escape sequences
are decoded. Because ``hex(ord('{')) == 0x7b``, the f-string
``f'\u007b4*10}'`` is decoded to ``f'{4*10}'``, which evaluates as
the integer 40::
Backslashes may not appear inside the expression portions of
f-strings, so you cannot use them, for example, to escape quotes
inside f-strings::
>>> f'\u007b4*10}'
'40'
>>> f'\x7b4*10}'
'40'
>>> f'\x7b4*10\N{RIGHT CURLY BRACKET}'
'40'
>>> f'{\'quoted string\'}'
File "<stdin>", line 1
SyntaxError: f-string expression part cannot include a backslash
These examples aren't generally useful, they're just to show that
escape sequences are processed before f-strings are parsed for
expressions.
You can use a different type of quote inside the expression::
>>> f'{"quoted string"}'
'quoted string'
Backslash escapes may appear inside the string portions of an
f-string.
Note that the correct way to have a literal brace appear in the
resulting string value is to double the brace::
@ -272,11 +268,8 @@ Due to Python's string tokenizing rules, the f-string
``f'abc {a['x']} def'`` is invalid. The tokenizer parses this as 3
tokens: ``f'abc {a['``, ``x``, and ``']} def'``. Just like regular
strings, this cannot be fixed by using raw strings. There are a number
of correct ways to write this f-string: with escaped single quotes::
f'abc {a[\'x\']} def'
With a different quote character::
of correct ways to write this f-string: with a different quote
character::
f"abc {a['x']} def"