From e9d8d6238ccc4ef30ff9575ceea9ce1e756186ec Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Tue, 22 Jul 2025 14:19:21 +0100 Subject: [PATCH 1/3] PEP 750 (template string literals) second pass --- Doc/glossary.rst | 2 + Doc/library/ast.rst | 33 +-- Doc/library/dis.rst | 8 +- Doc/library/stdtypes.rst | 7 +- Doc/library/string.rst | 18 +- Doc/library/string.templatelib.rst | 393 ++++++++++++++++------------- Doc/reference/lexical_analysis.rst | 60 ++--- Doc/tutorial/inputoutput.rst | 10 +- 8 files changed, 284 insertions(+), 247 deletions(-) diff --git a/Doc/glossary.rst b/Doc/glossary.rst index b7bd547d38fd1e..a4dc986c313c57 100644 --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -462,6 +462,7 @@ Glossary core and with user code. f-string + f-strings String literals prefixed with ``f`` or ``F`` are commonly called "f-strings" which is short for :ref:`formatted string literals `. See also :pep:`498`. @@ -1323,6 +1324,7 @@ Glossary See also :term:`borrowed reference`. t-string + t-strings String literals prefixed with ``t`` or ``T`` are commonly called "t-strings" which is short for :ref:`template string literals `. diff --git a/Doc/library/ast.rst b/Doc/library/ast.rst index b24459b5c6346f..22865670796308 100644 --- a/Doc/library/ast.rst +++ b/Doc/library/ast.rst @@ -289,9 +289,9 @@ Literals * ``conversion`` is an integer: * -1: no formatting - * 115 (``ord('s')``): ``!s`` string formatting - * 114 (``ord('r')``): ``!r`` repr formatting - * 97 (``ord('a')``): ``!a`` ASCII formatting + * 97: ``!a`` :func:`ASCII ` formatting (``ord('a')``) + * 114: ``!r`` :func:`repr` formatting (``ord('r')``) + * 115: ``!s`` :func:`string ` formatting (``ord('s')``) * ``format_spec`` is a :class:`JoinedStr` node representing the formatting of the value, or ``None`` if no format was specified. Both @@ -325,14 +325,18 @@ Literals Constant(value='.3')]))])) -.. class:: TemplateStr(values) +.. class:: TemplateStr(values, /) - A t-string, comprising a series of :class:`Interpolation` and :class:`Constant` - nodes. + .. versionadded:: 3.14 + + Node representing a template string literal, comprising a series of + :class:`Interpolation` and :class:`Constant` nodes. + These nodes may be any order, and do not need to be interleaved. .. doctest:: - >>> print(ast.dump(ast.parse('t"{name} finished {place:ordinal}"', mode='eval'), indent=4)) + >>> expr = ast.parse('t"{name} finished {place:ordinal}"', mode='eval') + >>> print(ast.dump(expr, indent=4)) Expression( body=TemplateStr( values=[ @@ -349,12 +353,11 @@ Literals values=[ Constant(value='ordinal')]))])) - .. versionadded:: 3.14 - +.. class:: Interpolation(value, str, conversion, format_spec=None) -.. class:: Interpolation(value, str, conversion, format_spec) + .. versionadded:: 3.14 - Node representing a single interpolation field in a t-string. + Node representing a single interpolation field in a template string literal. * ``value`` is any expression node (such as a literal, a variable, or a function call). @@ -362,16 +365,14 @@ Literals * ``conversion`` is an integer: * -1: no conversion - * 115: ``!s`` string conversion - * 114: ``!r`` repr conversion - * 97: ``!a`` ascii conversion + * 97: ``!a`` :func:`ASCII ` conversion (``ord('a')``) + * 114: ``!r`` :func:`repr` conversion (``ord('r')``) + * 115: ``!s`` :func:`string ` conversion (``ord('s')``) * ``format_spec`` is a :class:`JoinedStr` node representing the formatting of the value, or ``None`` if no format was specified. Both ``conversion`` and ``format_spec`` can be set at the same time. - .. versionadded:: 3.14 - .. class:: List(elts, ctx) Tuple(elts, ctx) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index ac8a911c40a860..7360f4aa804724 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -1122,8 +1122,8 @@ iterations of the loop. .. opcode:: BUILD_TEMPLATE - Constructs a new :class:`~string.templatelib.Template` from a tuple - of strings and a tuple of interpolations and pushes the resulting instance + Constructs a new :class:`~string.templatelib.Template` instance from a tuple + of strings and a tuple of interpolations and pushes the resulting object onto the stack:: interpolations = STACK.pop() @@ -1135,8 +1135,8 @@ iterations of the loop. .. opcode:: BUILD_INTERPOLATION (format) - Constructs a new :class:`~string.templatelib.Interpolation` from a - value and its source expression and pushes the resulting instance onto the + Constructs a new :class:`~string.templatelib.Interpolation` instance from a + value and its source expression and pushes the resulting object onto the stack. If no conversion or format specification is present, ``format`` is set to diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 90683c0b00d78a..a81a6704142dcc 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -2673,9 +2673,10 @@ For example: The formatting operations described here exhibit a variety of quirks that lead to a number of common errors (such as failing to display tuples and - dictionaries correctly). Using the newer :ref:`formatted string literals - `, the :meth:`str.format` interface, or :ref:`template strings - ($-strings) ` may help avoid these errors. + dictionaries correctly). + + Using :ref:`formatted string literals `, the :meth:`str.format` + interface, or :class:`string.Template` may help avoid these errors. Each of these alternatives provides their own trade-offs and benefits of simplicity, flexibility, and/or extensibility. diff --git a/Doc/library/string.rst b/Doc/library/string.rst index 83e8ee2722ed8a..6336a0ec47b91e 100644 --- a/Doc/library/string.rst +++ b/Doc/library/string.rst @@ -200,7 +200,7 @@ syntax for format strings (although in the case of :class:`Formatter`, subclasses can define their own format string syntax). The syntax is related to that of :ref:`formatted string literals ` and :ref:`template string literals `, but it is less sophisticated -and, in particular, does not support arbitrary expressions. +and, in particular, does not support arbitrary expressions in interpolations. .. index:: single: {} (curly brackets); in string formatting @@ -799,13 +799,15 @@ Template strings ($-strings) .. note:: - The feature described here was introduced in Python 2.4. It is unrelated - to, and should not be confused with, the newer - :ref:`template strings ` and - :ref:`t-string literal syntax ` introduced in Python 3.14. - T-string literals evaluate to instances of a different - :class:`~string.templatelib.Template` class, found in the - :mod:`string.templatelib` module. + The feature described here was introduced in Python 2.4; + a simple templating method based upon regular expressions. + It predates :meth:`str.format`, :ref:`formatted string literals `, + and :ref:`template string literals `. + + It is unrelated to template string literals (t-strings), + which were introduced in Python 3.14. + These evaluate to :class:`string.templatelib.Template` objects, + found in the :mod:`string.templatelib` module. Template strings provide simpler string substitutions as described in :pep:`292`. A primary use case for template strings is for diff --git a/Doc/library/string.templatelib.rst b/Doc/library/string.templatelib.rst index 31b90d75f411f0..226c9ff1e1b7b6 100644 --- a/Doc/library/string.templatelib.rst +++ b/Doc/library/string.templatelib.rst @@ -11,8 +11,8 @@ .. seealso:: * :ref:`Format strings ` - * :ref:`T-string literal syntax ` - + * :ref:`Template string literal (t-string) syntax ` + * :pep:`750` .. _template-strings: @@ -21,47 +21,49 @@ Template strings .. versionadded:: 3.14 -Template strings are a formatting mechanism that allows for deep control over -how strings are processed. You can create templates using -:ref:`t-string literal syntax `, which is identical to -:ref:`f-string syntax ` but uses a ``t`` instead of an ``f``. -While f-strings evaluate to ``str``, t-strings create a :class:`Template` -instance that gives you access to the static and interpolated (in curly braces) -parts of a string *before* they are combined. - - -.. _templatelib-template: +Template strings are a mechanism for custom string processing. +They have the full flexibility of Python's :ref:`f-strings`, +but return a :class:`Template` instance that gives access +to the static and interpolated (in curly braces) parts of a string +*before* they are combined. -Template --------- +To write a t-string, use a ``'t'`` prefix instead of an ``'f'``, like so: -The :class:`!Template` class describes the contents of a template string. +.. code-block:: pycon -:class:`!Template` instances are immutable: their attributes cannot be -reassigned. + >>> pi = 3.14 + >>> t't-strings are new in Python {pi!s}!' + Template( + strings=('t-strings are new in Python ', '!'), + interpolations=(Interpolation(3.14, 'pi', 's', ''),) + ) -.. class:: Template(*args) +Types +----- - Create a new :class:`!Template` object. +.. class:: Template - :param args: A mix of strings and :class:`Interpolation` instances in any order. - :type args: str | Interpolation + The :class:`!Template` class describes the contents of a template string. + It is immutable, meaning that attributes of a template cannot be reassigned. The most common way to create a :class:`!Template` instance is to use the - :ref:`t-string literal syntax `. This syntax is identical to that of - :ref:`f-strings ` except that it uses a ``t`` instead of an ``f``: + :ref:`template string literal syntax `. + This syntax is identical to that of :ref:`f-strings `, + except that it uses a ``t`` prefix in place of an ``f``: - >>> name = "World" - >>> template = t"Hello {name}!" + >>> name = 'World' + >>> template = t'Hello, {name}!' >>> type(template) - Templates ars stored as sequences of literal :attr:`~Template.strings` + Templates are stored as sequences of literal :attr:`~Template.strings` and dynamic :attr:`~Template.interpolations`. - A :attr:`~Template.values` attribute holds the interpolation values: + A :attr:`~Template.values` attribute holds the values of the interpolations: + >>> name = 'World' + >>> template = t'Hello, {name}!' >>> template.strings - ('Hello ', '!') + ('Hello, ', '!') >>> template.interpolations (Interpolation('World', ...),) >>> template.values @@ -69,230 +71,259 @@ reassigned. The :attr:`!strings` tuple has one more element than :attr:`!interpolations` and :attr:`!values`; the interpolations “belong” between the strings. - This may be easier to understand when tuples are aligned:: + This may be easier to understand when tuples are aligned - template.strings: ('Hello ', '!') - template.values: ( 'World', ) + .. code-block:: python - While literal syntax is the most common way to create :class:`!Template` - instances, it is also possible to create them directly using the constructor: + template.strings: ('Hello, ', '!') + template.values: ( 'World', ) - >>> from string.templatelib import Interpolation, Template - >>> name = "World" - >>> template = Template("Hello, ", Interpolation(name, "name"), "!") - >>> list(template) - ['Hello, ', Interpolation('World', 'name', None, ''), '!'] + .. rubric:: Attributes - If two or more consecutive strings are passed, they will be concatenated - into a single value in the :attr:`~Template.strings` attribute. For example, - the following code creates a :class:`Template` with a single final string: + .. attribute:: strings + :type: tuple[str, ...] - >>> from string.templatelib import Template - >>> template = Template("Hello ", "World", "!") - >>> template.strings - ('Hello World!',) + A :class:`tuple` of the static strings in the template. - If two or more consecutive interpolations are passed, they will be treated - as separate interpolations and an empty string will be inserted between them. - For example, the following code creates a template with empty placeholders - in the :attr:`~Template.strings` attribute: + >>> name = 'World' + >>> template = t'Hello, {name}!' + >>> template.strings + ('Hello, ', '!') - >>> from string.templatelib import Interpolation, Template - >>> template = Template(Interpolation("World", "name"), Interpolation("!", "punctuation")) - >>> template.strings - ('', '', '') + Empty strings *are* included in the tuple: - .. attribute:: strings - :type: tuple[str, ...] + >>> name = 'World' + >>> template = t'Hello, {name}{name}!' + >>> template.strings + ('Hello, ', '', '!') - A :ref:`tuple ` of the static strings in the template. + The ``strings`` tuple is never empty, and always contains one more + string than the ``interpolations`` and ``values`` tuples: - >>> name = "World" - >>> t"Hello {name}!".strings - ('Hello ', '!') + >>> t''.strings + ('',) + >>> t''.values + () + >>> t'{'cheese'}'.strings + ('', '') + >>> t'{'cheese'}'.values + ('cheese',) - Empty strings *are* included in the tuple: + .. attribute:: interpolations + :type: tuple[Interpolation, ...] - >>> name = "World" - >>> t"Hello {name}{name}!".strings - ('Hello ', '', '!') + A :class:`tuple` of the interpolations in the template. - The ``strings`` tuple is never empty, and always contains one more - string than the ``interpolations`` and ``values`` tuples: + >>> name = 'World' + >>> template = t'Hello, {name}!' + >>> template.interpolations + (Interpolation('World', 'name', None, ''),) - >>> t"".strings - ('',) - >>> t"".values - () - >>> t"{'cheese'}".strings - ('', '') - >>> t"{'cheese'}".values - ('cheese',) + The ``interpolations`` tuple may be empty and always contains one fewer + values than the ``strings`` tuple: - .. attribute:: interpolations - :type: tuple[Interpolation, ...] + >>> t'Hello!'.interpolations + () - A tuple of the interpolations in the template. + .. attribute:: values + :type: tuple[object, ...] - >>> name = "World" - >>> t"Hello {name}!".interpolations - (Interpolation('World', 'name', None, ''),) + A tuple of all interpolated values in the template. - The ``interpolations`` tuple may be empty and always contains one fewer - values than the ``strings`` tuple: + >>> name = 'World' + >>> template = t'Hello, {name}!' + >>> template.values + ('World',) - >>> t"Hello!".interpolations - () + The ``values`` tuple always has the same length as the + ``interpolations`` tuple. It is always equivalent to + ``tuple(i.value for i in template.interpolations)``. - .. attribute:: values - :type: tuple[Any, ...] + .. rubric:: Methods - A tuple of all interpolated values in the template. + .. method:: __new__(*args: str | Interpolation) - >>> name = "World" - >>> t"Hello {name}!".values - ('World',) + While literal syntax is the most common way to create a :class:`!Template`, + it is also possible to create them directly using the constructor: - The ``values`` tuple always has the same length as the - ``interpolations`` tuple. It is equivalent to - ``tuple(i.value for i in template.interpolations)``. + >>> from string.templatelib import Interpolation, Template + >>> name = 'World' + >>> template = Template('Hello, ', Interpolation(name, 'name'), '!') + >>> list(template) + ['Hello, ', Interpolation('World', 'name', None, ''), '!'] - .. describe:: iter(template) + If multiple strings are passed consecutively, they will be concatenated + into a single value in the :attr:`~Template.strings` attribute. For example, + the following code creates a :class:`Template` with a single final string: - Iterate over the template, yielding each string and - :class:`Interpolation` in order. + >>> from string.templatelib import Template + >>> template = Template('Hello, ', 'World', '!') + >>> template.strings + ('Hello, World!',) - >>> name = "World" - >>> list(t"Hello {name}!") - ['Hello ', Interpolation('World', 'name', None, ''), '!'] + If multiple interpolations are passed consecutively, they will be treated + as separate interpolations and an empty string will be inserted between them. + For example, the following code creates a template with empty placeholders + in the :attr:`~Template.strings` attribute: - Empty strings are *not* included in the iteration: + >>> from string.templatelib import Interpolation, Template + >>> template = Template( + ... Interpolation('World', 'name'), + ... Interpolation('!', 'punctuation'), + ... ) + >>> template.strings + ('', '', '') - >>> name = "World" - >>> list(t"Hello {name}{name}") - ['Hello ', Interpolation('World', 'name', None, ''), Interpolation('World', 'name', None, '')] + .. describe:: iter(template) - .. describe:: template + other - template += other + Iterate over the template, yielding each non-empty string and + :class:`Interpolation` in the correct order: - Concatenate this template with another, returning a new - :class:`!Template` instance: + >>> name = 'World' + >>> list(t'Hello, {name}!') + ['Hello, ', Interpolation('World', 'name', None, ''), '!'] - >>> name = "World" - >>> list(t"Hello " + t"there {name}!") - ['Hello there ', Interpolation('World', 'name', None, ''), '!'] + .. caution:: - Concatenation between a :class:`!Template` and a ``str`` is *not* supported. - This is because it is ambiguous whether the string should be treated as - a static string or an interpolation. If you want to concatenate a - :class:`!Template` with a string, you should either wrap the string - directly in a :class:`!Template` (to treat it as a static string) or use - an :class:`!Interpolation` (to treat it as dynamic): + Empty strings are **not** included in the iteration: - >>> from string.templatelib import Template, Interpolation - >>> template = t"Hello " - >>> # Treat "there " as a static string - >>> template += Template("there ") - >>> # Treat name as an interpolation - >>> name = "World" - >>> template += Template(Interpolation(name, "name")) - >>> list(template) - ['Hello there ', Interpolation('World', 'name', None, '')] + >>> name = 'World' + >>> list(t'Hello, {name}{name}!') + [ + 'Hello, ', + Interpolation('World', 'name', None, ''), + Interpolation('World', 'name', None, ''), + '!', + ] + .. describe:: template + other + template += other -.. class:: Interpolation(value, expression="", conversion=None, format_spec="") + Concatenate this template with another, returning a new + :class:`!Template` instance: - Create a new :class:`!Interpolation` object. + >>> name = 'World' + >>> list(t'Hello ' + t'there {name}!') + ['Hello there ', Interpolation('World', 'name', None, ''), '!'] - :param value: The evaluated, in-scope result of the interpolation. - :type value: object + Concatenating a :class:`!Template` and a ``str`` is **not** supported. + This is because it is unclear whether the string should be treated as + a static string or an interpolation. + If you want to concatenate a :class:`!Template` with a string, + you should either wrap the string directly in a :class:`!Template` + (to treat it as a static string) + or use an :class:`!Interpolation` (to treat it as dynamic): - :param expression: The text of a valid Python expression, or an empty string. - :type expression: str + >>> from string.templatelib import Template, Interpolation + >>> template = t'Hello ' + >>> # Treat 'there ' as a static string + >>> template += Template('there ') + >>> # Treat name as an interpolation + >>> name = 'World' + >>> template += Template(Interpolation(name, 'name')) + >>> list(template) + ['Hello there ', Interpolation('World', 'name', None, '')] - :param conversion: The optional :ref:`conversion ` to be used, one of r, s, and a. - :type conversion: ``Literal["a", "r", "s"] | None`` - :param format_spec: An optional, arbitrary string used as the :ref:`format specification ` to present the value. - :type format_spec: str +.. class:: Interpolation The :class:`!Interpolation` type represents an expression inside a template string. + It is immutable, meaning that attributes of an interpolation cannot be reassigned. - :class:`!Interpolation` instances are immutable: their attributes cannot be - reassigned. + Interpolations support pattern matching, allowing you to match against + their attributes with the :ref:`match statement `: + + >>> from string.templatelib import Interpolation + >>> interpolation = t'{1. + 2.:.2f}'.interpolations[0] + >>> interpolation + Interpolation(3.0, '1. + 2.', None, '.2f') + >>> match interpolation: + ... case Interpolation(value, expression, conversion, format_spec): + ... print(value, expression, conversion, format_spec, sep=' | ') + ... + 3.0 | 1. + 2. | None | .2f + + .. rubric:: Attributes .. attribute:: value + :type: object - :returns: The evaluated value of the interpolation. - :type: object + The evaluated value of the interpolation. - >>> t"{1 + 2}".interpolations[0].value - 3 + >>> t'{1 + 2}'.interpolations[0].value + 3 .. attribute:: expression + :type: str - :returns: The text of a valid Python expression, or an empty string. - :type: str + The text of a valid Python expression, or an empty string. - The :attr:`~Interpolation.expression` is the original text of the - interpolation's Python expression, if the interpolation was created - from a t-string literal. Developers creating interpolations manually - should either set this to an empty string or choose a suitable valid - Python expression. + The :attr:`.expression` is the original text of the + interpolation's Python expression, if the interpolation was created + from a t-string literal. Developers creating interpolations manually + should either set this to an empty string or choose a suitable valid + Python expression. - >>> t"{1 + 2}".interpolations[0].expression - '1 + 2' + >>> t'{1 + 2}'.interpolations[0].expression + '1 + 2' .. attribute:: conversion + :type: typing.Literal['a', 'r', 's'] | None - :returns: The conversion to apply to the value, or ``None``. - :type: ``Literal["a", "r", "s"] | None`` + The conversion to apply to the value, or ``None``. - The :attr:`!Interpolation.conversion` is the optional conversion to apply - to the value: + The :attr:`!conversion` is the optional conversion to apply + to the value: - >>> t"{1 + 2!a}".interpolations[0].conversion - 'a' + >>> t'{1 + 2!a}'.interpolations[0].conversion + 'a' - .. note:: + .. note:: Unlike f-strings, where conversions are applied automatically, the expected behavior with t-strings is that code that *processes* the :class:`!Template` will decide how to interpret and whether to apply - the :attr:`!Interpolation.conversion`. + the :attr:`!conversion`. + For convenience, the :func:`convert` function can be used to mimic + f-string conversion semantics. .. attribute:: format_spec + :type: str - :returns: The format specification to apply to the value. - :type: str + The format specification to apply to the value. - The :attr:`!Interpolation.format_spec` is an optional, arbitrary string - used as the format specification to present the value: + The :attr:`!format_spec` is an optional, arbitrary string + used as the format specification to present the value: - >>> t"{1 + 2:.2f}".interpolations[0].format_spec - '.2f' + >>> t'{1 + 2:.2f}'.interpolations[0].format_spec + '.2f' - .. note:: + .. note:: Unlike f-strings, where format specifications are applied automatically via the :func:`format` protocol, the expected behavior with - t-strings is that code that *processes* the :class:`!Template` will + t-strings is that code that *processes* the interpolation will decide how to interpret and whether to apply the format specification. - As a result, :attr:`!Interpolation.format_spec` values in - :class:`!Template` instances can be arbitrary strings, even those that - do not necessarily conform to the rules of Python's :func:`format` - protocol. + As a result, :attr:`!format_spec` values in interpolations + can be arbitrary strings, + including those that do not conform to the :func:`format` protocol. - Interpolations support pattern matching, allowing you to match against - their attributes with the :ref:`match statement `: + .. rubric:: Methods - >>> from string.templatelib import Interpolation - >>> interpolation = Interpolation(3.0, "1 + 2", None, ".2f") - >>> match interpolation: - ... case Interpolation(value, expression, conversion, format_spec): - ... print(value, expression, conversion, format_spec) - ... - 3.0 1 + 2 None .2f + .. method:: __new__(value: object, \ + expression: str, \ + conversion: typing.Literal['a', 'r', 's'] | None = None, \ + format_spec: str = '') + + Create a new :class:`!Interpolation` object from component parts. + + :param value: The evaluated, in-scope result of the interpolation. + :param expression: The text of a valid Python expression, + or an empty string. + :param conversion: The :ref:`conversion ` to be used, + one of ``None``, ``'a'``, ``'r'``, or ``'s'``. + :param format_spec: An optional, arbitrary string used as the + :ref:`format specification ` to present the value. Helper functions @@ -306,8 +337,8 @@ Helper functions Three conversion flags are currently supported: - * ``'s'`` which calls :func:`str` on the value, - * ``'r'`` which calls :func:`repr`, and - * ``'a'`` which calls :func:`ascii`. + * ``'s'`` which calls :func:`str` on the value (like ``!s``), + * ``'r'`` which calls :func:`repr` (like ``!r``), and + * ``'a'`` which calls :func:`ascii` (like ``!a``). If the conversion flag is ``None``, *obj* is returned unchanged. diff --git a/Doc/reference/lexical_analysis.rst b/Doc/reference/lexical_analysis.rst index a7f8e5392b7e71..d3cf643ad292d9 100644 --- a/Doc/reference/lexical_analysis.rst +++ b/Doc/reference/lexical_analysis.rst @@ -561,9 +561,9 @@ escapes are not treated specially. single: f'; formatted string literal single: f"; formatted string literal -A string literal with ``f`` or ``F`` in its prefix is a -:dfn:`formatted string literal`; see :ref:`f-strings`. The ``f`` may be -combined with ``r``, but not with ``b`` or ``u``, therefore raw +A string literal with ``'f'`` or ``'F'`` in its prefix is a +:dfn:`formatted string literal`; see :ref:`f-strings`. The ``'f'`` may be +combined with ``'r'``, but not with ``'b'`` or ``'u'``, therefore raw formatted strings are possible, but formatted bytes literals are not. In triple-quoted literals, unescaped newlines and quotes are allowed (and are @@ -756,7 +756,7 @@ f-strings .. versionadded:: 3.6 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'``. These strings may contain replacement fields, which are expressions delimited by curly braces ``{}``. While other string literals always have a constant value, formatted strings are really expressions evaluated at run time. @@ -922,37 +922,37 @@ t-strings .. versionadded:: 3.14 A :dfn:`template string literal` or :dfn:`t-string` 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 `, with -the following differences: +that is prefixed with ``'t'`` or ``'T'``. +These strings follow the same syntax and evaluation rules as +:ref:`formatted string literals `, with the following differences: -- Rather than evaluating to a ``str`` object, t-strings evaluate to a - :class:`~string.templatelib.Template` object from the - :mod:`string.templatelib` module. +* 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. +* 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, +* 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 expression ``{precision}`` before setting the ``format_spec`` - attribute of the resulting :class:`!Interpolation` object; if ``precision`` - is (for example) ``2``, the resulting format specifier will be ``'.2f'``. - -- When the equal sign ``'='`` is provided in an interpolation expression, the - resulting :class:`~string.templatelib.Template` object will have the expression - text along with a ``'='`` character placed in its - :attr:`~string.templatelib.Template.strings` attribute. The - :attr:`~string.templatelib.Template.interpolations` attribute will also - contain an ``Interpolation`` instance for the expression. By default, the - :attr:`~string.templatelib.Interpolation.conversion` attribute will be set to - ``'r'`` (that is, :func:`repr`), unless there is a conversion explicitly - specified (in which case it overrides the default) or a format specifier is - provided (in which case, the ``conversion`` defaults to ``None``). + 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. .. _numbers: diff --git a/Doc/tutorial/inputoutput.rst b/Doc/tutorial/inputoutput.rst index ea546c6a29df44..a00f06cf46c41a 100644 --- a/Doc/tutorial/inputoutput.rst +++ b/Doc/tutorial/inputoutput.rst @@ -95,11 +95,11 @@ Some examples:: >>> repr((x, y, ('spam', 'eggs'))) "(32.5, 40000, ('spam', 'eggs'))" -The :mod:`string` module also contains support for so-called -:ref:`$-strings ` that offer yet another way to -substitute values into strings, using placeholders like ``$x`` and replacing -them with values from a dictionary. This syntax is easy to use, although -it offers much less control of the formatting. +The :mod:`string` module contains support for a simple templating approach +based upon regular expressions, via :class:`string.Template`. +This offers yet another way to substitute values into strings, +using placeholders like ``$x`` and replacing them with values from a dictionary. +This syntax is easy to use, although it offers much less control for formatting. .. index:: single: formatted string literal From 2497cab7626f61b9e04974267fb830f8bfd0986b Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Tue, 22 Jul 2025 19:44:37 +0100 Subject: [PATCH 2/3] doctest --- Doc/library/string.templatelib.rst | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/Doc/library/string.templatelib.rst b/Doc/library/string.templatelib.rst index 226c9ff1e1b7b6..dd080b8e51dd59 100644 --- a/Doc/library/string.templatelib.rst +++ b/Doc/library/string.templatelib.rst @@ -188,13 +188,11 @@ Types Empty strings are **not** included in the iteration: >>> name = 'World' - >>> list(t'Hello, {name}{name}!') - [ - 'Hello, ', - Interpolation('World', 'name', None, ''), - Interpolation('World', 'name', None, ''), - '!', - ] + >>> list(t'Hello, {name}{name}!') # doctest: +NORMALIZE_WHITESPACE + ['Hello, ', + Interpolation('World', 'name', None, ''), + Interpolation('World', 'name', None, ''), + '!'] .. describe:: template + other template += other From 53b541b68848e73d167503851f0f7792b8bb53ba Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Wed, 23 Jul 2025 13:17:38 +0100 Subject: [PATCH 3/3] Update Doc/library/ast.rst --- Doc/library/ast.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/ast.rst b/Doc/library/ast.rst index 22865670796308..29d10efba869ea 100644 --- a/Doc/library/ast.rst +++ b/Doc/library/ast.rst @@ -289,9 +289,9 @@ Literals * ``conversion`` is an integer: * -1: no formatting - * 97: ``!a`` :func:`ASCII ` formatting (``ord('a')``) - * 114: ``!r`` :func:`repr` formatting (``ord('r')``) - * 115: ``!s`` :func:`string ` formatting (``ord('s')``) + * 97 (``ord('a')``): ``!a`` :func:`ASCII ` formatting + * 114 (``ord('r')``): ``!r`` :func:`repr` formatting + * 115 (``ord('s')``): ``!s`` :func:`string ` formatting * ``format_spec`` is a :class:`JoinedStr` node representing the formatting of the value, or ``None`` if no format was specified. Both pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy