-
-
Notifications
You must be signed in to change notification settings - Fork 33.8k
gh-135676: Reword the f-string (and t-string) section #137469
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 18 commits
d4381aa
80ad85c
e44fa66
86bf94b
faf05a1
687fe58
9f9d29c
1e0c84a
e7b57b5
3733e0c
d593940
0d8a917
366ecfc
5fdb129
e88843c
394f835
f2db8f9
6468a97
681112d
9e1290f
ebe2a6b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2528,6 +2528,8 @@ expression support in the :mod:`re` module). | |
| single: : (colon); in formatted string literal | ||
| single: = (equals); for help in debugging using string literals | ||
|
|
||
| .. _stdtypes-fstrings: | ||
|
|
||
| Formatted String Literals (f-strings) | ||
| ------------------------------------- | ||
|
|
||
|
|
@@ -2536,123 +2538,147 @@ Formatted String Literals (f-strings) | |
| The :keyword:`await` and :keyword:`async for` can be used in expressions | ||
| within f-strings. | ||
| .. versionchanged:: 3.8 | ||
| Added the debugging operator (``=``) | ||
| 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. | ||
|
|
||
| An :dfn:`f-string` (formally a :dfn:`formatted string literal`) is | ||
| a string literal that is prefixed with ``f`` or ``F``. | ||
| This type of string literal allows embedding arbitrary Python expressions | ||
| within *replacement fields*, which are delimited by curly brackets (``{}``). | ||
| These expressions are evaluated at runtime, similarly to :meth:`str.format`, | ||
| and are converted into regular :class:`str` objects. | ||
| For example: | ||
| This type of string literal allows embedding the results of arbitrary Python | ||
| expressions within *replacement fields*, which are delimited by curly | ||
| brackets (``{}``). | ||
| Each replacement field must contain an expression, optionally followed by: | ||
|
|
||
| .. 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' | ||
| >>> nationality = 'Spanish' | ||
| >>> f'{who.title()} expects the {nationality} Inquisition!' | ||
| 'Nobody expects the Spanish Inquisition!' | ||
| See the :ref:`Lexical Analysis section on f-strings <f-strings>` for details | ||
| on the syntax of these fields. | ||
|
|
||
| It is also possible to use a multi line f-string: | ||
| Debug specifier | ||
| ^^^^^^^^^^^^^^^ | ||
|
|
||
| .. doctest:: | ||
| .. versionadded:: 3.8 | ||
|
|
||
| >>> f'''This is a string | ||
| ... on two lines''' | ||
| 'This is a string\non two lines' | ||
| If a debug specifier -- an equal sign (``=``) -- appears after the replacement | ||
| field expression, the resulting f-string will contain the expression's source, | ||
| 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 | ||
| can contain any Python expression: | ||
| >>> number = 14.3 | ||
| >>> 'number=14.3' | ||
| number=14.3 | ||
|
|
||
| .. doctest:: | ||
|
|
||
| >>> nationality = 'Spanish' | ||
| >>> f'The {nationality} Inquisition!' | ||
| 'The Spanish Inquisition!' | ||
| Whitespace before, inside and after the expression, as well as whitespace | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps highlight a bit. I didn't realize that the whitespace was significant before and after within the {}.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you have a suggestion on how to highlight this? FWIW, I don't think this is a very important detail, since it only affects formatting of debug output. |
||
| after the equal sign, is significant --- it is retained in the result:: | ||
|
|
||
| To include a literal ``{`` or ``}``, use a double bracket: | ||
| >>> f'{ number - 4 = }' | ||
| ' number - 4 = 10.3' | ||
|
|
||
| .. doctest:: | ||
|
|
||
| >>> x = 42 | ||
| >>> f'{{x}} is {x}' | ||
| '{x} is 42' | ||
| Conversion specifier | ||
| ^^^^^^^^^^^^^^^^^^^^ | ||
|
|
||
| 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:: | ||
| By default, the value of a replacement field expression is converted to | ||
| string using :func:`str`:: | ||
encukou marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| >>> from fractions import Fraction | ||
| >>> f'{Fraction(1, 3)}' | ||
| >>> one_third = Fraction(1, 3) | ||
| >>> f'{one_third}' | ||
| '1/3' | ||
|
|
||
| To use an explicit conversion, use the ``!`` (exclamation mark) operator, | ||
| followed by any of the valid formats, which are: | ||
| When a debug specifier but no format specifier is used, the default conversion | ||
| instead uses :func:`repr`:: | ||
|
|
||
| ========== ============== | ||
| Conversion Meaning | ||
| ========== ============== | ||
| ``!a`` :func:`ascii` | ||
| ``!r`` :func:`repr` | ||
| ``!s`` :func:`str` | ||
| ========== ============== | ||
| >>> f'{one_third = }' | ||
| 'one_third = Fraction(1, 3)' | ||
|
|
||
| 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 | ||
| >>> f'{Fraction(1, 3)!s}' | ||
| For example:: | ||
|
|
||
| >>> str(one_third) | ||
StanFromIreland marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| '1/3' | ||
| >>> f'{Fraction(1, 3)!r}' | ||
| >>> repr(one_third) | ||
| '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, | ||
| by using the equals sign (``=``) after the expression. | ||
| 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:: | ||
| >>> f'{one_third!s} is {one_third!r}' | ||
| '1/3 is Fraction(1, 3)' | ||
|
|
||
| >>> from fractions import Fraction | ||
| >>> calculation = Fraction(1, 3) | ||
| >>> f'{calculation=}' | ||
| 'calculation=Fraction(1, 3)' | ||
| >>> f'{calculation = }' | ||
| 'calculation = Fraction(1, 3)' | ||
| >>> f'{calculation = !s}' | ||
| 'calculation = 1/3' | ||
|
|
||
| Once the output has been evaluated, it can be formatted using a | ||
| :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: | ||
| >>> string = "¡kočka 😸!" | ||
| >>> ascii(string) | ||
| "'\\xa1ko\\u010dka \\U0001f638!'" | ||
|
|
||
| .. doctest:: | ||
| >>> 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 | ||
| >>> f'{Fraction(1, 7):.6f}' | ||
| '0.142857' | ||
| >>> f'{Fraction(1, 7):_^+10}' | ||
| '___+1/7___' | ||
| >>> one_third = Fraction(1, 3) | ||
| >>> f'{one_third:.6f}' | ||
| '0.333333' | ||
| >>> f'{one_third:_^+10}' | ||
| '___+1/3___' | ||
| >>> >>> f'{one_third!r:_^20}' | ||
| '___Fraction(1, 3)___' | ||
| >>> f'{one_third = :~>10}~' | ||
| 'one_third = ~~~~~~~1/3~' | ||
|
|
||
| .. _stdtypes-tstrings: | ||
|
|
||
| Template String Literals (t-strings) | ||
| ------------------------------------ | ||
|
|
||
| An :dfn:`t-string` (formally a :dfn:`template string literal`) is | ||
| a string literal that is prefixed with ``t`` or ``T``. | ||
|
|
||
| These strings follow the same syntax and evaluation rules as | ||
| :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: | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.