mirror of
https://github.com/python/cpython.git
synced 2025-12-08 06:10:17 +00:00
gh-135676: Reword the f-string (and t-string) section (GH-137469)
Much of the information was duplicated in stdtypes.rst; this PR keeps lexical/syntactical details in Lexical Analysis and the evaluation & runtime behaviour in Standard types, with cross-references between the two. Since the t-string section only listed differences from f-strings, and the grammar for the two is equivalent, that section was moved to Standard types almost entirely. Co-authored-by: Blaise Pabon <blaise@gmail.com> Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Co-authored-by: Stan Ulbrych <89152624+StanFromIreland@users.noreply.github.com>
This commit is contained in:
parent
f6f456f950
commit
aea5531583
3 changed files with 323 additions and 234 deletions
|
|
@ -2656,6 +2656,8 @@ expression support in the :mod:`re` module).
|
||||||
single: : (colon); in formatted string literal
|
single: : (colon); in formatted string literal
|
||||||
single: = (equals); for help in debugging using string literals
|
single: = (equals); for help in debugging using string literals
|
||||||
|
|
||||||
|
.. _stdtypes-fstrings:
|
||||||
|
|
||||||
Formatted String Literals (f-strings)
|
Formatted String Literals (f-strings)
|
||||||
-------------------------------------
|
-------------------------------------
|
||||||
|
|
||||||
|
|
@ -2664,123 +2666,147 @@ Formatted String Literals (f-strings)
|
||||||
The :keyword:`await` and :keyword:`async for` can be used in expressions
|
The :keyword:`await` and :keyword:`async for` can be used in expressions
|
||||||
within f-strings.
|
within f-strings.
|
||||||
.. versionchanged:: 3.8
|
.. versionchanged:: 3.8
|
||||||
Added the debugging operator (``=``)
|
Added the debug specifier (``=``)
|
||||||
.. versionchanged:: 3.12
|
.. versionchanged:: 3.12
|
||||||
Many restrictions on expressions within f-strings have been removed.
|
Many restrictions on expressions within f-strings have been removed.
|
||||||
Notably, nested strings, comments, and backslashes are now permitted.
|
Notably, nested strings, comments, and backslashes are now permitted.
|
||||||
|
|
||||||
An :dfn:`f-string` (formally a :dfn:`formatted string literal`) is
|
An :dfn:`f-string` (formally a :dfn:`formatted string literal`) is
|
||||||
a string literal that is prefixed with ``f`` or ``F``.
|
a string literal that is prefixed with ``f`` or ``F``.
|
||||||
This type of string literal allows embedding arbitrary Python expressions
|
This type of string literal allows embedding the results of arbitrary Python
|
||||||
within *replacement fields*, which are delimited by curly brackets (``{}``).
|
expressions within *replacement fields*, which are delimited by curly
|
||||||
These expressions are evaluated at runtime, similarly to :meth:`str.format`,
|
brackets (``{}``).
|
||||||
and are converted into regular :class:`str` objects.
|
Each replacement field must contain an expression, optionally followed by:
|
||||||
For example:
|
|
||||||
|
|
||||||
.. doctest::
|
* a *debug specifier* -- an equal sign (``=``);
|
||||||
|
* a *conversion specifier* -- ``!s``, ``!r`` or ``!a``; and/or
|
||||||
|
* a *format specifier* prefixed with a colon (``:``).
|
||||||
|
|
||||||
>>> who = 'nobody'
|
See the :ref:`Lexical Analysis section on f-strings <f-strings>` for details
|
||||||
>>> nationality = 'Spanish'
|
on the syntax of these fields.
|
||||||
>>> f'{who.title()} expects the {nationality} Inquisition!'
|
|
||||||
'Nobody expects the Spanish Inquisition!'
|
|
||||||
|
|
||||||
It is also possible to use a multi line f-string:
|
Debug specifier
|
||||||
|
^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
.. doctest::
|
.. versionadded:: 3.8
|
||||||
|
|
||||||
>>> f'''This is a string
|
If a debug specifier -- an equal sign (``=``) -- appears after the replacement
|
||||||
... on two lines'''
|
field expression, the resulting f-string will contain the expression's source,
|
||||||
'This is a string\non two lines'
|
the equal sign, and the value of the expression.
|
||||||
|
This is often useful for debugging::
|
||||||
|
|
||||||
A single opening curly bracket, ``'{'``, marks a *replacement field* that
|
>>> number = 14.3
|
||||||
can contain any Python expression:
|
>>> f'{number=}'
|
||||||
|
'number=14.3'
|
||||||
|
|
||||||
.. doctest::
|
Whitespace before, inside and after the expression, as well as whitespace
|
||||||
|
after the equal sign, is significant --- it is retained in the result::
|
||||||
|
|
||||||
>>> nationality = 'Spanish'
|
>>> f'{ number - 4 = }'
|
||||||
>>> f'The {nationality} Inquisition!'
|
' number - 4 = 10.3'
|
||||||
'The Spanish Inquisition!'
|
|
||||||
|
|
||||||
To include a literal ``{`` or ``}``, use a double bracket:
|
|
||||||
|
|
||||||
.. doctest::
|
Conversion specifier
|
||||||
|
^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
>>> x = 42
|
By default, the value of a replacement field expression is converted to
|
||||||
>>> f'{{x}} is {x}'
|
a string using :func:`str`::
|
||||||
'{x} is 42'
|
|
||||||
|
|
||||||
Functions can also be used, and :ref:`format specifiers <formatstrings>`:
|
|
||||||
|
|
||||||
.. doctest::
|
|
||||||
|
|
||||||
>>> from math import sqrt
|
|
||||||
>>> f'√2 \N{ALMOST EQUAL TO} {sqrt(2):.5f}'
|
|
||||||
'√2 ≈ 1.41421'
|
|
||||||
|
|
||||||
Any non-string expression is converted using :func:`str`, by default:
|
|
||||||
|
|
||||||
.. doctest::
|
|
||||||
|
|
||||||
>>> from fractions import Fraction
|
>>> from fractions import Fraction
|
||||||
>>> f'{Fraction(1, 3)}'
|
>>> one_third = Fraction(1, 3)
|
||||||
|
>>> f'{one_third}'
|
||||||
'1/3'
|
'1/3'
|
||||||
|
|
||||||
To use an explicit conversion, use the ``!`` (exclamation mark) operator,
|
When a debug specifier but no format specifier is used, the default conversion
|
||||||
followed by any of the valid formats, which are:
|
instead uses :func:`repr`::
|
||||||
|
|
||||||
========== ==============
|
>>> f'{one_third = }'
|
||||||
Conversion Meaning
|
'one_third = Fraction(1, 3)'
|
||||||
========== ==============
|
|
||||||
``!a`` :func:`ascii`
|
|
||||||
``!r`` :func:`repr`
|
|
||||||
``!s`` :func:`str`
|
|
||||||
========== ==============
|
|
||||||
|
|
||||||
For example:
|
The conversion can be specified explicitly using one of these specifiers:
|
||||||
|
|
||||||
.. doctest::
|
* ``!s`` for :func:`str`
|
||||||
|
* ``!r`` for :func:`repr`
|
||||||
|
* ``!a`` for :func:`ascii`
|
||||||
|
|
||||||
>>> from fractions import Fraction
|
For example::
|
||||||
>>> f'{Fraction(1, 3)!s}'
|
|
||||||
|
>>> str(one_third)
|
||||||
'1/3'
|
'1/3'
|
||||||
>>> f'{Fraction(1, 3)!r}'
|
>>> repr(one_third)
|
||||||
'Fraction(1, 3)'
|
'Fraction(1, 3)'
|
||||||
>>> question = '¿Dónde está el Presidente?'
|
|
||||||
>>> print(f'{question!a}')
|
|
||||||
'\xbfD\xf3nde est\xe1 el Presidente?'
|
|
||||||
|
|
||||||
While debugging it may be helpful to see both the expression and its value,
|
>>> f'{one_third!s} is {one_third!r}'
|
||||||
by using the equals sign (``=``) after the expression.
|
'1/3 is Fraction(1, 3)'
|
||||||
This preserves spaces within the brackets, and can be used with a converter.
|
|
||||||
By default, the debugging operator uses the :func:`repr` (``!r``) conversion.
|
|
||||||
For example:
|
|
||||||
|
|
||||||
.. doctest::
|
>>> string = "¡kočka 😸!"
|
||||||
|
>>> ascii(string)
|
||||||
|
"'\\xa1ko\\u010dka \\U0001f638!'"
|
||||||
|
|
||||||
|
>>> f'{string = !a}'
|
||||||
|
"string = '\\xa1ko\\u010dka \\U0001f638!'"
|
||||||
|
|
||||||
|
|
||||||
|
Format specifier
|
||||||
|
^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
After the expression has been evaluated, and possibly converted using an
|
||||||
|
explicit conversion specifier, it is formatted using the :func:`format` function.
|
||||||
|
If the replacement field includes a *format specifier* introduced by a colon
|
||||||
|
(``:``), the specifier is passed to :func:`!format` as the second argument.
|
||||||
|
The result of :func:`!format` is then used as the final value for the
|
||||||
|
replacement field. For example::
|
||||||
|
|
||||||
>>> from fractions import Fraction
|
>>> from fractions import Fraction
|
||||||
>>> calculation = Fraction(1, 3)
|
>>> one_third = Fraction(1, 3)
|
||||||
>>> f'{calculation=}'
|
>>> f'{one_third:.6f}'
|
||||||
'calculation=Fraction(1, 3)'
|
'0.333333'
|
||||||
>>> f'{calculation = }'
|
>>> f'{one_third:_^+10}'
|
||||||
'calculation = Fraction(1, 3)'
|
'___+1/3___'
|
||||||
>>> f'{calculation = !s}'
|
>>> >>> f'{one_third!r:_^20}'
|
||||||
'calculation = 1/3'
|
'___Fraction(1, 3)___'
|
||||||
|
>>> f'{one_third = :~>10}~'
|
||||||
|
'one_third = ~~~~~~~1/3~'
|
||||||
|
|
||||||
Once the output has been evaluated, it can be formatted using a
|
.. _stdtypes-tstrings:
|
||||||
:ref:`format specifier <formatstrings>` following a colon (``':'``).
|
|
||||||
After the expression has been evaluated, and possibly converted to a string,
|
|
||||||
the :meth:`!__format__` method of the result is called with the format specifier,
|
|
||||||
or the empty string if no format specifier is given.
|
|
||||||
The formatted result is then used as the final value for the replacement field.
|
|
||||||
For example:
|
|
||||||
|
|
||||||
.. doctest::
|
Template String Literals (t-strings)
|
||||||
|
------------------------------------
|
||||||
|
|
||||||
>>> from fractions import Fraction
|
An :dfn:`t-string` (formally a :dfn:`template string literal`) is
|
||||||
>>> f'{Fraction(1, 7):.6f}'
|
a string literal that is prefixed with ``t`` or ``T``.
|
||||||
'0.142857'
|
|
||||||
>>> f'{Fraction(1, 7):_^+10}'
|
These strings follow the same syntax and evaluation rules as
|
||||||
'___+1/7___'
|
:ref:`formatted string literals <stdtypes-fstrings>`,
|
||||||
|
with for the following differences:
|
||||||
|
|
||||||
|
* Rather than evaluating to a ``str`` object, template string literals evaluate
|
||||||
|
to a :class:`string.templatelib.Template` object.
|
||||||
|
|
||||||
|
* The :func:`format` protocol is not used.
|
||||||
|
Instead, the format specifier and conversions (if any) are passed to
|
||||||
|
a new :class:`~string.templatelib.Interpolation` object that is created
|
||||||
|
for each evaluated expression.
|
||||||
|
It is up to code that processes the resulting :class:`~string.templatelib.Template`
|
||||||
|
object to decide how to handle format specifiers and conversions.
|
||||||
|
|
||||||
|
* Format specifiers containing nested replacement fields are evaluated eagerly,
|
||||||
|
prior to being passed to the :class:`~string.templatelib.Interpolation` object.
|
||||||
|
For instance, an interpolation of the form ``{amount:.{precision}f}`` will
|
||||||
|
evaluate the inner expression ``{precision}`` to determine the value of the
|
||||||
|
``format_spec`` attribute.
|
||||||
|
If ``precision`` were to be ``2``, the resulting format specifier
|
||||||
|
would be ``'.2f'``.
|
||||||
|
|
||||||
|
* When the equals sign ``'='`` is provided in an interpolation expression,
|
||||||
|
the text of the expression is appended to the literal string that precedes
|
||||||
|
the relevant interpolation.
|
||||||
|
This includes the equals sign and any surrounding whitespace.
|
||||||
|
The :class:`!Interpolation` instance for the expression will be created as
|
||||||
|
normal, except that :attr:`~string.templatelib.Interpolation.conversion` will
|
||||||
|
be set to '``r``' (:func:`repr`) by default.
|
||||||
|
If an explicit conversion or format specifier are provided,
|
||||||
|
this will override the default behaviour.
|
||||||
|
|
||||||
|
|
||||||
.. _old-string-formatting:
|
.. _old-string-formatting:
|
||||||
|
|
|
||||||
|
|
@ -174,7 +174,7 @@ Formally:
|
||||||
.. grammar-snippet::
|
.. grammar-snippet::
|
||||||
:group: python-grammar
|
:group: python-grammar
|
||||||
|
|
||||||
strings: ( `STRING` | fstring)+ | tstring+
|
strings: ( `STRING` | `fstring`)+ | `tstring`+
|
||||||
|
|
||||||
This feature is defined at the syntactical level, so it only works with literals.
|
This feature is defined at the syntactical level, so it only works with literals.
|
||||||
To concatenate string expressions at run time, the '+' operator may be used::
|
To concatenate string expressions at run time, the '+' operator may be used::
|
||||||
|
|
|
||||||
|
|
@ -345,7 +345,15 @@ Whitespace between tokens
|
||||||
|
|
||||||
Except at the beginning of a logical line or in string literals, the whitespace
|
Except at the beginning of a logical line or in string literals, the whitespace
|
||||||
characters space, tab and formfeed can be used interchangeably to separate
|
characters space, tab and formfeed can be used interchangeably to separate
|
||||||
tokens. Whitespace is needed between two tokens only if their concatenation
|
tokens:
|
||||||
|
|
||||||
|
.. grammar-snippet::
|
||||||
|
:group: python-grammar
|
||||||
|
|
||||||
|
whitespace: ' ' | tab | formfeed
|
||||||
|
|
||||||
|
|
||||||
|
Whitespace is needed between two tokens only if their concatenation
|
||||||
could otherwise be interpreted as a different token. For example, ``ab`` is one
|
could otherwise be interpreted as a different token. For example, ``ab`` is one
|
||||||
token, but ``a b`` is two tokens. However, ``+a`` and ``+ a`` both produce
|
token, but ``a b`` is two tokens. However, ``+a`` and ``+ a`` both produce
|
||||||
two tokens, ``+`` and ``a``, as ``+a`` is not a valid token.
|
two tokens, ``+`` and ``a``, as ``+a`` is not a valid token.
|
||||||
|
|
@ -1032,124 +1040,59 @@ f-strings
|
||||||
---------
|
---------
|
||||||
|
|
||||||
.. versionadded:: 3.6
|
.. versionadded:: 3.6
|
||||||
|
.. versionchanged:: 3.7
|
||||||
|
The :keyword:`await` and :keyword:`async for` can be used in expressions
|
||||||
|
within f-strings.
|
||||||
|
.. versionchanged:: 3.8
|
||||||
|
Added the debug specifier (``=``)
|
||||||
|
.. versionchanged:: 3.12
|
||||||
|
Many restrictions on expressions within f-strings have been removed.
|
||||||
|
Notably, nested strings, comments, and backslashes are now permitted.
|
||||||
|
|
||||||
A :dfn:`formatted string literal` or :dfn:`f-string` is a string literal
|
A :dfn:`formatted string literal` or :dfn:`f-string` is a string literal
|
||||||
that is prefixed with '``f``' or '``F``'. These strings may contain
|
that is prefixed with '``f``' or '``F``'.
|
||||||
replacement fields, which are expressions delimited by curly braces ``{}``.
|
Unlike other string literals, f-strings do not have a constant value.
|
||||||
While other string literals always have a constant value, formatted strings
|
They may contain *replacement fields* delimited by curly braces ``{}``.
|
||||||
are really expressions evaluated at run time.
|
Replacement fields contain expressions which are evaluated at run time.
|
||||||
|
For example::
|
||||||
|
|
||||||
Escape sequences are decoded like in ordinary string literals (except when
|
>>> who = 'nobody'
|
||||||
a literal is also marked as a raw string). After decoding, the grammar
|
>>> nationality = 'Spanish'
|
||||||
for the contents of the string is:
|
>>> f'{who.title()} expects the {nationality} Inquisition!'
|
||||||
|
'Nobody expects the Spanish Inquisition!'
|
||||||
|
|
||||||
.. productionlist:: python-grammar
|
Any doubled curly braces (``{{`` or ``}}``) outside replacement fields
|
||||||
f_string: (`literal_char` | "{{" | "}}" | `replacement_field`)*
|
are replaced with the corresponding single curly brace::
|
||||||
replacement_field: "{" `f_expression` ["="] ["!" `conversion`] [":" `format_spec`] "}"
|
|
||||||
f_expression: (`conditional_expression` | "*" `or_expr`)
|
|
||||||
: ("," `conditional_expression` | "," "*" `or_expr`)* [","]
|
|
||||||
: | `yield_expression`
|
|
||||||
conversion: "s" | "r" | "a"
|
|
||||||
format_spec: (`literal_char` | `replacement_field`)*
|
|
||||||
literal_char: <any code point except "{", "}" or NULL>
|
|
||||||
|
|
||||||
The parts of the string outside curly braces are treated literally,
|
>>> print(f'{{...}}')
|
||||||
except that any doubled curly braces ``'{{'`` or ``'}}'`` are replaced
|
{...}
|
||||||
with the corresponding single curly brace. A single opening curly
|
|
||||||
bracket ``'{'`` marks a replacement field, which starts with a
|
Other characters outside replacement fields are treated like in ordinary
|
||||||
Python expression. To display both the expression text and its value after
|
string literals.
|
||||||
evaluation, (useful in debugging), an equal sign ``'='`` may be added after the
|
This means that escape sequences are decoded (except when a literal is
|
||||||
expression. A conversion field, introduced by an exclamation point ``'!'`` may
|
also marked as a raw string), and newlines are possible in triple-quoted
|
||||||
follow. A format specifier may also be appended, introduced by a colon ``':'``.
|
f-strings::
|
||||||
A replacement field ends with a closing curly bracket ``'}'``.
|
|
||||||
|
>>> name = 'Galahad'
|
||||||
|
>>> favorite_color = 'blue'
|
||||||
|
>>> print(f'{name}:\t{favorite_color}')
|
||||||
|
Galahad: blue
|
||||||
|
>>> print(rf"C:\Users\{name}")
|
||||||
|
C:\Users\Galahad
|
||||||
|
>>> print(f'''Three shall be the number of the counting
|
||||||
|
... and the number of the counting shall be three.''')
|
||||||
|
Three shall be the number of the counting
|
||||||
|
and the number of the counting shall be three.
|
||||||
|
|
||||||
Expressions in formatted string literals are treated like regular
|
Expressions in formatted string literals are treated like regular
|
||||||
Python expressions surrounded by parentheses, with a few exceptions.
|
Python expressions.
|
||||||
An empty expression is not allowed, and both :keyword:`lambda` and
|
|
||||||
assignment expressions ``:=`` must be surrounded by explicit parentheses.
|
|
||||||
Each expression is evaluated in the context where the formatted string literal
|
Each expression is evaluated in the context where the formatted string literal
|
||||||
appears, in order from left to right. Replacement expressions can contain
|
appears, in order from left to right.
|
||||||
newlines in both single-quoted and triple-quoted f-strings and they can contain
|
An empty expression is not allowed, and both :keyword:`lambda` and
|
||||||
comments. Everything that comes after a ``#`` inside a replacement field
|
assignment expressions ``:=`` must be surrounded by explicit parentheses::
|
||||||
is a comment (even closing braces and quotes). In that case, replacement fields
|
|
||||||
must be closed in a different line.
|
|
||||||
|
|
||||||
.. code-block:: text
|
|
||||||
|
|
||||||
>>> f"abc{a # This is a comment }"
|
|
||||||
... + 3}"
|
|
||||||
'abc5'
|
|
||||||
|
|
||||||
.. versionchanged:: 3.7
|
|
||||||
Prior to Python 3.7, an :keyword:`await` expression and comprehensions
|
|
||||||
containing an :keyword:`async for` clause were illegal in the expressions
|
|
||||||
in formatted string literals due to a problem with the implementation.
|
|
||||||
|
|
||||||
.. versionchanged:: 3.12
|
|
||||||
Prior to Python 3.12, comments were not allowed inside f-string replacement
|
|
||||||
fields.
|
|
||||||
|
|
||||||
When the equal sign ``'='`` is provided, the output will have the expression
|
|
||||||
text, the ``'='`` and the evaluated value. Spaces after the opening brace
|
|
||||||
``'{'``, within the expression and after the ``'='`` are all retained in the
|
|
||||||
output. By default, the ``'='`` causes the :func:`repr` of the expression to be
|
|
||||||
provided, unless there is a format specified. When a format is specified it
|
|
||||||
defaults to the :func:`str` of the expression unless a conversion ``'!r'`` is
|
|
||||||
declared.
|
|
||||||
|
|
||||||
.. versionadded:: 3.8
|
|
||||||
The equal sign ``'='``.
|
|
||||||
|
|
||||||
If a conversion is specified, the result of evaluating the expression
|
|
||||||
is converted before formatting. Conversion ``'!s'`` calls :func:`str` on
|
|
||||||
the result, ``'!r'`` calls :func:`repr`, and ``'!a'`` calls :func:`ascii`.
|
|
||||||
|
|
||||||
The result is then formatted using the :func:`format` protocol. The
|
|
||||||
format specifier is passed to the :meth:`~object.__format__` method of the
|
|
||||||
expression or conversion result. An empty string is passed when the
|
|
||||||
format specifier is omitted. The formatted result is then included in
|
|
||||||
the final value of the whole string.
|
|
||||||
|
|
||||||
Top-level format specifiers may include nested replacement fields. These nested
|
|
||||||
fields may include their own conversion fields and :ref:`format specifiers
|
|
||||||
<formatspec>`, but may not include more deeply nested replacement fields. The
|
|
||||||
:ref:`format specifier mini-language <formatspec>` is the same as that used by
|
|
||||||
the :meth:`str.format` method.
|
|
||||||
|
|
||||||
Formatted string literals may be concatenated, but replacement fields
|
|
||||||
cannot be split across literals.
|
|
||||||
|
|
||||||
Some examples of formatted string literals::
|
|
||||||
|
|
||||||
>>> name = "Fred"
|
|
||||||
>>> f"He said his name is {name!r}."
|
|
||||||
"He said his name is 'Fred'."
|
|
||||||
>>> f"He said his name is {repr(name)}." # repr() is equivalent to !r
|
|
||||||
"He said his name is 'Fred'."
|
|
||||||
>>> width = 10
|
|
||||||
>>> precision = 4
|
|
||||||
>>> value = decimal.Decimal("12.34567")
|
|
||||||
>>> f"result: {value:{width}.{precision}}" # nested fields
|
|
||||||
'result: 12.35'
|
|
||||||
>>> today = datetime(year=2017, month=1, day=27)
|
|
||||||
>>> f"{today:%B %d, %Y}" # using date format specifier
|
|
||||||
'January 27, 2017'
|
|
||||||
>>> f"{today=:%B %d, %Y}" # using date format specifier and debugging
|
|
||||||
'today=January 27, 2017'
|
|
||||||
>>> number = 1024
|
|
||||||
>>> f"{number:#0x}" # using integer format specifier
|
|
||||||
'0x400'
|
|
||||||
>>> foo = "bar"
|
|
||||||
>>> f"{ foo = }" # preserves whitespace
|
|
||||||
" foo = 'bar'"
|
|
||||||
>>> line = "The mill's closed"
|
|
||||||
>>> f"{line = }"
|
|
||||||
'line = "The mill\'s closed"'
|
|
||||||
>>> f"{line = :20}"
|
|
||||||
"line = The mill's closed "
|
|
||||||
>>> f"{line = !r:20}"
|
|
||||||
'line = "The mill\'s closed" '
|
|
||||||
|
|
||||||
|
>>> f'{(half := 1/2)}, {half * 42}'
|
||||||
|
'0.5, 21.0'
|
||||||
|
|
||||||
Reusing the outer f-string quoting type inside a replacement field is
|
Reusing the outer f-string quoting type inside a replacement field is
|
||||||
permitted::
|
permitted::
|
||||||
|
|
@ -1158,10 +1101,6 @@ permitted::
|
||||||
>>> f"abc {a["x"]} def"
|
>>> f"abc {a["x"]} def"
|
||||||
'abc 2 def'
|
'abc 2 def'
|
||||||
|
|
||||||
.. versionchanged:: 3.12
|
|
||||||
Prior to Python 3.12, reuse of the same quoting type of the outer f-string
|
|
||||||
inside a replacement field was not possible.
|
|
||||||
|
|
||||||
Backslashes are also allowed in replacement fields and are evaluated the same
|
Backslashes are also allowed in replacement fields and are evaluated the same
|
||||||
way as in any other context::
|
way as in any other context::
|
||||||
|
|
||||||
|
|
@ -1172,23 +1111,84 @@ way as in any other context::
|
||||||
b
|
b
|
||||||
c
|
c
|
||||||
|
|
||||||
.. versionchanged:: 3.12
|
It is possible to nest f-strings::
|
||||||
Prior to Python 3.12, backslashes were not permitted inside an f-string
|
|
||||||
replacement field.
|
|
||||||
|
|
||||||
Formatted string literals cannot be used as docstrings, even if they do not
|
>>> name = 'world'
|
||||||
include expressions.
|
>>> f'Repeated:{f' hello {name}' * 3}'
|
||||||
|
'Repeated: hello world hello world hello world'
|
||||||
|
|
||||||
::
|
Portable Python programs should not use more than 5 levels of nesting.
|
||||||
|
|
||||||
|
.. impl-detail::
|
||||||
|
|
||||||
|
CPython does not limit nesting of f-strings.
|
||||||
|
|
||||||
|
Replacement expressions can contain newlines in both single-quoted and
|
||||||
|
triple-quoted f-strings and they can contain comments.
|
||||||
|
Everything that comes after a ``#`` inside a replacement field
|
||||||
|
is a comment (even closing braces and quotes).
|
||||||
|
This means that replacement fields with comments must be closed in a
|
||||||
|
different line:
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
>>> a = 2
|
||||||
|
>>> f"abc{a # This comment }" continues until the end of the line
|
||||||
|
... + 3}"
|
||||||
|
'abc5'
|
||||||
|
|
||||||
|
After the expression, replacement fields may optionally contain:
|
||||||
|
|
||||||
|
* a *debug specifier* -- an equal sign (``=``), optionally surrounded by
|
||||||
|
whitespace on one or both sides;
|
||||||
|
* a *conversion specifier* -- ``!s``, ``!r`` or ``!a``; and/or
|
||||||
|
* a *format specifier* prefixed with a colon (``:``).
|
||||||
|
|
||||||
|
See the :ref:`Standard Library section on f-strings <stdtypes-fstrings>`
|
||||||
|
for details on how these fields are evaluated.
|
||||||
|
|
||||||
|
As that section explains, *format specifiers* are passed as the second argument
|
||||||
|
to the :func:`format` function to format a replacement field value.
|
||||||
|
For example, they can be used to specify a field width and padding characters
|
||||||
|
using the :ref:`Format Specification Mini-Language <formatspec>`::
|
||||||
|
|
||||||
|
>>> number = 14.3
|
||||||
|
>>> f'{number:20.7f}'
|
||||||
|
' 14.3000000'
|
||||||
|
|
||||||
|
Top-level format specifiers may include nested replacement fields::
|
||||||
|
|
||||||
|
>>> field_size = 20
|
||||||
|
>>> precision = 7
|
||||||
|
>>> f'{number:{field_size}.{precision}f}'
|
||||||
|
' 14.3000000'
|
||||||
|
|
||||||
|
These nested fields may include their own conversion fields and
|
||||||
|
:ref:`format specifiers <formatspec>`::
|
||||||
|
|
||||||
|
>>> number = 3
|
||||||
|
>>> f'{number:{field_size}}'
|
||||||
|
' 3'
|
||||||
|
>>> f'{number:{field_size:05}}'
|
||||||
|
'00000000000000000003'
|
||||||
|
|
||||||
|
However, these nested fields may not include more deeply nested replacement
|
||||||
|
fields.
|
||||||
|
|
||||||
|
Formatted string literals cannot be used as :term:`docstrings <docstring>`,
|
||||||
|
even if they do not include expressions::
|
||||||
|
|
||||||
>>> def foo():
|
>>> def foo():
|
||||||
... f"Not a docstring"
|
... f"Not a docstring"
|
||||||
...
|
...
|
||||||
>>> foo.__doc__ is None
|
>>> print(foo.__doc__)
|
||||||
True
|
None
|
||||||
|
|
||||||
See also :pep:`498` for the proposal that added formatted string literals,
|
.. seealso::
|
||||||
and :meth:`str.format`, which uses a related format string mechanism.
|
|
||||||
|
* :pep:`498` -- Literal String Interpolation
|
||||||
|
* :pep:`701` -- Syntactic formalization of f-strings
|
||||||
|
* :meth:`str.format`, which uses a related format string mechanism.
|
||||||
|
|
||||||
|
|
||||||
.. _t-strings:
|
.. _t-strings:
|
||||||
|
|
@ -1201,36 +1201,99 @@ t-strings
|
||||||
|
|
||||||
A :dfn:`template string literal` or :dfn:`t-string` is a string literal
|
A :dfn:`template string literal` or :dfn:`t-string` is a string literal
|
||||||
that is prefixed with '``t``' or '``T``'.
|
that is prefixed with '``t``' or '``T``'.
|
||||||
These strings follow the same syntax and evaluation rules as
|
These strings follow the same syntax rules as
|
||||||
:ref:`formatted string literals <f-strings>`, with the following differences:
|
:ref:`formatted string literals <f-strings>`.
|
||||||
|
For differences in evaluation rules, see the
|
||||||
|
:ref:`Standard Library section on t-strings <stdtypes-tstrings>`
|
||||||
|
|
||||||
* Rather than evaluating to a ``str`` object, template string literals evaluate
|
|
||||||
to a :class:`string.templatelib.Template` object.
|
|
||||||
|
|
||||||
* The :func:`format` protocol is not used.
|
Formal grammar for f-strings
|
||||||
Instead, the format specifier and conversions (if any) are passed to
|
----------------------------
|
||||||
a new :class:`~string.templatelib.Interpolation` object that is created
|
|
||||||
for each evaluated expression.
|
|
||||||
It is up to code that processes the resulting :class:`~string.templatelib.Template`
|
|
||||||
object to decide how to handle format specifiers and conversions.
|
|
||||||
|
|
||||||
* Format specifiers containing nested replacement fields are evaluated eagerly,
|
F-strings are handled partly by the :term:`lexical analyzer`, which produces the
|
||||||
prior to being passed to the :class:`~string.templatelib.Interpolation` object.
|
tokens :py:data:`~token.FSTRING_START`, :py:data:`~token.FSTRING_MIDDLE`
|
||||||
For instance, an interpolation of the form ``{amount:.{precision}f}`` will
|
and :py:data:`~token.FSTRING_END`, and partly by the parser, which handles
|
||||||
evaluate the inner expression ``{precision}`` to determine the value of the
|
expressions in the replacement field.
|
||||||
``format_spec`` attribute.
|
The exact way the work is split is a CPython implementation detail.
|
||||||
If ``precision`` were to be ``2``, the resulting format specifier
|
|
||||||
would be ``'.2f'``.
|
|
||||||
|
|
||||||
* When the equals sign ``'='`` is provided in an interpolation expression,
|
Correspondingly, the f-string grammar is a mix of
|
||||||
the text of the expression is appended to the literal string that precedes
|
:ref:`lexical and syntactic definitions <notation-lexical-vs-syntactic>`.
|
||||||
the relevant interpolation.
|
|
||||||
This includes the equals sign and any surrounding whitespace.
|
Whitespace is significant in these situations:
|
||||||
The :class:`!Interpolation` instance for the expression will be created as
|
|
||||||
normal, except that :attr:`~string.templatelib.Interpolation.conversion` will
|
* There may be no whitespace in :py:data:`~token.FSTRING_START` (between
|
||||||
be set to '``r``' (:func:`repr`) by default.
|
the prefix and quote).
|
||||||
If an explicit conversion or format specifier are provided,
|
* Whitespace in :py:data:`~token.FSTRING_MIDDLE` is part of the literal
|
||||||
this will override the default behaviour.
|
string contents.
|
||||||
|
* In ``fstring_replacement_field``, if ``f_debug_specifier`` is present,
|
||||||
|
all whitespace after the opening brace until the ``f_debug_specifier``,
|
||||||
|
as well as whitespace immediatelly following ``f_debug_specifier``,
|
||||||
|
is retained as part of the expression.
|
||||||
|
|
||||||
|
.. impl-detail::
|
||||||
|
|
||||||
|
The expression is not handled in the tokenization phase; it is
|
||||||
|
retrieved from the source code using locations of the ``{`` token
|
||||||
|
and the token after ``=``.
|
||||||
|
|
||||||
|
|
||||||
|
The ``FSTRING_MIDDLE`` definition uses
|
||||||
|
:ref:`negative lookaheads <lexical-lookaheads>` (``!``)
|
||||||
|
to indicate special characters (backslash, newline, ``{``, ``}``) and
|
||||||
|
sequences (``f_quote``).
|
||||||
|
|
||||||
|
.. grammar-snippet::
|
||||||
|
:group: python-grammar
|
||||||
|
|
||||||
|
fstring: `FSTRING_START` `fstring_middle`* `FSTRING_END`
|
||||||
|
|
||||||
|
FSTRING_START: `fstringprefix` ("'" | '"' | "'''" | '"""')
|
||||||
|
FSTRING_END: `f_quote`
|
||||||
|
fstringprefix: <("f" | "fr" | "rf"), case-insensitive>
|
||||||
|
f_debug_specifier: '='
|
||||||
|
f_quote: <the quote character(s) used in FSTRING_START>
|
||||||
|
|
||||||
|
fstring_middle:
|
||||||
|
| `fstring_replacement_field`
|
||||||
|
| `FSTRING_MIDDLE`
|
||||||
|
FSTRING_MIDDLE:
|
||||||
|
| (!"\" !`newline` !'{' !'}' !`f_quote`) `source_character`
|
||||||
|
| `stringescapeseq`
|
||||||
|
| "{{"
|
||||||
|
| "}}"
|
||||||
|
| <newline, in triple-quoted f-strings only>
|
||||||
|
fstring_replacement_field:
|
||||||
|
| '{' `f_expression` [`f_debug_specifier`] [`fstring_conversion`]
|
||||||
|
[`fstring_full_format_spec`] '}'
|
||||||
|
fstring_conversion:
|
||||||
|
| "!" ("s" | "r" | "a")
|
||||||
|
fstring_full_format_spec:
|
||||||
|
| ':' `fstring_format_spec`*
|
||||||
|
fstring_format_spec:
|
||||||
|
| `FSTRING_MIDDLE`
|
||||||
|
| `fstring_replacement_field`
|
||||||
|
f_expression:
|
||||||
|
| ','.(`conditional_expression` | "*" `or_expr`)+ [","]
|
||||||
|
| `yield_expression`
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
In the above grammar snippet, the ``f_quote`` and ``FSTRING_MIDDLE`` rules
|
||||||
|
are context-sensitive -- they depend on the contents of ``FSTRING_START``
|
||||||
|
of the nearest enclosing ``fstring``.
|
||||||
|
|
||||||
|
Constructing a more traditional formal grammar from this template is left
|
||||||
|
as an exercise for the reader.
|
||||||
|
|
||||||
|
The grammar for t-strings is identical to the one for f-strings, with *t*
|
||||||
|
instead of *f* at the beginning of rule and token names and in the prefix.
|
||||||
|
|
||||||
|
.. grammar-snippet::
|
||||||
|
:group: python-grammar
|
||||||
|
|
||||||
|
tstring: TSTRING_START tstring_middle* TSTRING_END
|
||||||
|
|
||||||
|
<rest of the t-string grammar is omitted; see above>
|
||||||
|
|
||||||
|
|
||||||
.. _numbers:
|
.. _numbers:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue