2015-08-07 21:42:37 -04:00
|
|
|
|
PEP: 498
|
2015-08-30 09:16:20 -04:00
|
|
|
|
Title: Literal String Interpolation
|
2015-08-07 21:33:01 -04:00
|
|
|
|
Version: $Revision$
|
|
|
|
|
Last-Modified: $Date$
|
|
|
|
|
Author: Eric V. Smith <eric@trueblade.com>
|
2017-04-15 16:16:09 -04:00
|
|
|
|
Status: Final
|
2015-08-07 21:33:01 -04:00
|
|
|
|
Type: Standards Track
|
|
|
|
|
Content-Type: text/x-rst
|
|
|
|
|
Created: 01-Aug-2015
|
|
|
|
|
Python-Version: 3.6
|
2016-11-06 11:26:59 -05:00
|
|
|
|
Post-History: 07-Aug-2015, 30-Aug-2015, 04-Sep-2015, 19-Sep-2015, 06-Nov-2016
|
2015-09-08 20:38:45 -04:00
|
|
|
|
Resolution: https://mail.python.org/pipermail/python-dev/2015-September/141526.html
|
2015-08-07 21:33:01 -04:00
|
|
|
|
|
|
|
|
|
Abstract
|
|
|
|
|
========
|
|
|
|
|
|
|
|
|
|
Python supports multiple ways to format text strings. These include
|
2015-08-29 16:20:18 -04:00
|
|
|
|
%-formatting [#]_, ``str.format()`` [#]_, and ``string.Template``
|
|
|
|
|
[#]_. Each of these methods have their advantages, but in addition
|
|
|
|
|
have disadvantages that make them cumbersome to use in practice. This
|
|
|
|
|
PEP proposed to add a new string formatting mechanism: Literal String
|
2015-09-05 13:50:27 -04:00
|
|
|
|
Interpolation. In this PEP, such strings will be referred to as
|
2015-08-07 21:33:01 -04:00
|
|
|
|
"f-strings", taken from the leading character used to denote such
|
2015-08-30 09:16:20 -04:00
|
|
|
|
strings, and standing for "formatted strings".
|
2015-08-07 21:33:01 -04:00
|
|
|
|
|
2015-08-11 09:32:15 -04:00
|
|
|
|
This PEP does not propose to remove or deprecate any of the existing
|
|
|
|
|
string formatting mechanisms.
|
|
|
|
|
|
2017-03-29 14:07:50 -04:00
|
|
|
|
F-strings provide a way to embed expressions inside string literals,
|
2015-08-21 18:35:55 -04:00
|
|
|
|
using a minimal syntax. It should be noted that an f-string is really
|
|
|
|
|
an expression evaluated at run time, not a constant value. In Python
|
2015-09-04 21:25:59 -04:00
|
|
|
|
source code, an f-string is a literal string, prefixed with 'f', which
|
2015-08-21 18:35:55 -04:00
|
|
|
|
contains expressions inside braces. The expressions are replaced with
|
|
|
|
|
their values. Some examples are::
|
2015-08-07 21:33:01 -04:00
|
|
|
|
|
|
|
|
|
>>> import datetime
|
|
|
|
|
>>> name = 'Fred'
|
|
|
|
|
>>> age = 50
|
|
|
|
|
>>> anniversary = datetime.date(1991, 10, 12)
|
|
|
|
|
>>> f'My name is {name}, my age next year is {age+1}, my anniversary is {anniversary:%A, %B %d, %Y}.'
|
|
|
|
|
'My name is Fred, my age next year is 51, my anniversary is Saturday, October 12, 1991.'
|
|
|
|
|
>>> f'He said his name is {name!r}.'
|
|
|
|
|
"He said his name is 'Fred'."
|
|
|
|
|
|
2015-09-04 21:25:59 -04:00
|
|
|
|
A similar feature was proposed in PEP 215. PEP 215 proposed to support
|
|
|
|
|
a subset of Python expressions, and did not support the type-specific
|
|
|
|
|
string formatting (the ``__format__()`` method) which was introduced
|
|
|
|
|
with PEP 3101.
|
2015-08-07 21:33:01 -04:00
|
|
|
|
|
|
|
|
|
Rationale
|
|
|
|
|
=========
|
|
|
|
|
|
|
|
|
|
This PEP is driven by the desire to have a simpler way to format
|
|
|
|
|
strings in Python. The existing ways of formatting are either error
|
|
|
|
|
prone, inflexible, or cumbersome.
|
|
|
|
|
|
|
|
|
|
%-formatting is limited as to the types it supports. Only ints, strs,
|
|
|
|
|
and doubles can be formatted. All other types are either not
|
|
|
|
|
supported, or converted to one of these types before formatting. In
|
|
|
|
|
addition, there's a well-known trap where a single value is passed::
|
|
|
|
|
|
|
|
|
|
>>> msg = 'disk failure'
|
|
|
|
|
>>> 'error: %s' % msg
|
|
|
|
|
'error: disk failure'
|
|
|
|
|
|
|
|
|
|
But if msg were ever to be a tuple, the same code would fail::
|
|
|
|
|
|
|
|
|
|
>>> msg = ('disk failure', 32)
|
|
|
|
|
>>> 'error: %s' % msg
|
|
|
|
|
Traceback (most recent call last):
|
|
|
|
|
File "<stdin>", line 1, in <module>
|
|
|
|
|
TypeError: not all arguments converted during string formatting
|
|
|
|
|
|
|
|
|
|
To be defensive, the following code should be used::
|
|
|
|
|
|
|
|
|
|
>>> 'error: %s' % (msg,)
|
|
|
|
|
"error: ('disk failure', 32)"
|
|
|
|
|
|
2015-08-29 16:20:18 -04:00
|
|
|
|
``str.format()`` was added to address some of these problems with
|
2015-08-07 21:33:01 -04:00
|
|
|
|
%-formatting. In particular, it uses normal function call syntax (and
|
2015-08-24 09:20:50 -04:00
|
|
|
|
therefor supports multiple parameters) and it is extensible through
|
2015-08-29 16:20:18 -04:00
|
|
|
|
the ``__format__()`` method on the object being converted to a
|
2015-09-04 21:25:59 -04:00
|
|
|
|
string. See PEP 3101 for a detailed rationale. This PEP reuses much of
|
2015-08-29 16:20:18 -04:00
|
|
|
|
the ``str.format()`` syntax and machinery, in order to provide
|
|
|
|
|
continuity with an existing Python string formatting mechanism.
|
2015-08-07 21:33:01 -04:00
|
|
|
|
|
2015-08-29 16:20:18 -04:00
|
|
|
|
However, ``str.format()`` is not without its issues. Chief among them
|
|
|
|
|
is its verbosity. For example, the text ``value`` is repeated here::
|
2015-08-07 21:33:01 -04:00
|
|
|
|
|
|
|
|
|
>>> value = 4 * 20
|
|
|
|
|
>>> 'The value is {value}.'.format(value=value)
|
|
|
|
|
'The value is 80.'
|
|
|
|
|
|
2015-09-04 21:25:59 -04:00
|
|
|
|
Even in its simplest form there is a bit of boilerplate, and the value
|
|
|
|
|
that's inserted into the placeholder is sometimes far removed from
|
|
|
|
|
where the placeholder is situated::
|
2015-08-07 21:33:01 -04:00
|
|
|
|
|
|
|
|
|
>>> 'The value is {}.'.format(value)
|
|
|
|
|
'The value is 80.'
|
|
|
|
|
|
|
|
|
|
With an f-string, this becomes::
|
|
|
|
|
|
|
|
|
|
>>> f'The value is {value}.'
|
|
|
|
|
'The value is 80.'
|
|
|
|
|
|
2017-07-06 13:17:04 -04:00
|
|
|
|
F-strings provide a concise, readable way to include the value of
|
2015-08-29 16:02:17 -04:00
|
|
|
|
Python expressions inside strings.
|
2015-08-07 21:33:01 -04:00
|
|
|
|
|
2015-08-29 16:20:18 -04:00
|
|
|
|
In this sense, ``string.Template`` and %-formatting have similar
|
|
|
|
|
shortcomings to ``str.format()``, but also support fewer formatting
|
|
|
|
|
options. In particular, they do not support the ``__format__``
|
|
|
|
|
protocol, so that there is no way to control how a specific object is
|
|
|
|
|
converted to a string, nor can it be extended to additional types that
|
|
|
|
|
want to control how they are converted to strings (such as ``Decimal``
|
|
|
|
|
and ``datetime``). This example is not possible with
|
|
|
|
|
``string.Template``::
|
2015-08-21 05:13:39 -04:00
|
|
|
|
|
|
|
|
|
>>> value = 1234
|
2016-12-26 01:56:00 -05:00
|
|
|
|
>>> f'input={value:#06x}'
|
2015-08-21 05:13:39 -04:00
|
|
|
|
'input=0x04d2'
|
|
|
|
|
|
2015-08-29 16:20:18 -04:00
|
|
|
|
And neither %-formatting nor ``string.Template`` can control
|
|
|
|
|
formatting such as::
|
2015-08-21 05:13:39 -04:00
|
|
|
|
|
|
|
|
|
>>> date = datetime.date(1991, 10, 12)
|
|
|
|
|
>>> f'{date} was on a {date:%A}'
|
|
|
|
|
'1991-10-12 was on a Saturday'
|
2015-08-07 21:33:01 -04:00
|
|
|
|
|
|
|
|
|
No use of globals() or locals()
|
|
|
|
|
-------------------------------
|
|
|
|
|
|
|
|
|
|
In the discussions on python-dev [#]_, a number of solutions where
|
|
|
|
|
presented that used locals() and globals() or their equivalents. All
|
|
|
|
|
of these have various problems. Among these are referencing variables
|
|
|
|
|
that are not otherwise used in a closure. Consider::
|
|
|
|
|
|
|
|
|
|
>>> def outer(x):
|
|
|
|
|
... def inner():
|
|
|
|
|
... return 'x={x}'.format_map(locals())
|
|
|
|
|
... return inner
|
|
|
|
|
...
|
|
|
|
|
>>> outer(42)()
|
|
|
|
|
Traceback (most recent call last):
|
|
|
|
|
File "<stdin>", line 1, in <module>
|
|
|
|
|
File "<stdin>", line 3, in inner
|
|
|
|
|
KeyError: 'x'
|
|
|
|
|
|
|
|
|
|
This returns an error because the compiler has not added a reference
|
|
|
|
|
to x inside the closure. You need to manually add a reference to x in
|
|
|
|
|
order for this to work::
|
|
|
|
|
|
|
|
|
|
>>> def outer(x):
|
|
|
|
|
... def inner():
|
|
|
|
|
... x
|
|
|
|
|
... return 'x={x}'.format_map(locals())
|
|
|
|
|
... return inner
|
|
|
|
|
...
|
|
|
|
|
>>> outer(42)()
|
|
|
|
|
'x=42'
|
|
|
|
|
|
2015-08-20 20:02:45 -04:00
|
|
|
|
In addition, using locals() or globals() introduces an information
|
|
|
|
|
leak. A called routine that has access to the callers locals() or
|
|
|
|
|
globals() has access to far more information than needed to do the
|
|
|
|
|
string interpolation.
|
|
|
|
|
|
2015-08-07 21:33:01 -04:00
|
|
|
|
Guido stated [#]_ that any solution to better string interpolation
|
|
|
|
|
would not use locals() or globals().
|
|
|
|
|
|
|
|
|
|
Specification
|
|
|
|
|
=============
|
|
|
|
|
|
|
|
|
|
In source code, f-strings are string literals that are prefixed by the
|
2015-09-10 04:03:33 -04:00
|
|
|
|
letter 'f' or 'F'. Everywhere this PEP uses 'f', 'F' may also be
|
2016-11-06 11:18:17 -05:00
|
|
|
|
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'.
|
2015-09-04 21:25:59 -04:00
|
|
|
|
|
|
|
|
|
When tokenizing source files, f-strings use the same rules as normal
|
|
|
|
|
strings, raw strings, binary strings, and triple quoted strings. That
|
|
|
|
|
is, the string must end with the same character that it started with:
|
|
|
|
|
if it starts with a single quote it must end with a single quote, etc.
|
|
|
|
|
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).
|
2015-09-04 20:28:35 -04:00
|
|
|
|
|
2016-11-06 11:18:17 -05:00
|
|
|
|
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
|
2015-09-12 20:08:18 -04:00
|
|
|
|
braces ``'{{'`` or ``'}}'`` inside literal portions of an f-string are
|
2016-11-19 12:07:19 -05:00
|
|
|
|
replaced by the corresponding single brace. Doubled literal opening
|
|
|
|
|
braces do not signify the start of an expression. A single closing
|
|
|
|
|
curly brace ``'}'`` in the literal portion of a string is an error:
|
2016-11-19 12:16:38 -05:00
|
|
|
|
literal closing curly braces must be doubled ``'}}'`` in order to
|
|
|
|
|
represent a single closing brace.
|
2015-08-07 21:33:01 -04:00
|
|
|
|
|
2016-11-06 11:18:17 -05:00
|
|
|
|
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 [#]_.
|
2015-09-19 11:24:19 -04:00
|
|
|
|
|
2016-11-06 11:18:17 -05:00
|
|
|
|
Backslashes may not appear anywhere within expressions. Comments,
|
|
|
|
|
using the ``'#'`` character, are not allowed inside an expression.
|
2015-09-05 17:07:48 -04:00
|
|
|
|
|
2016-11-06 11:18:17 -05:00
|
|
|
|
Following each expression, an optional type conversion may be
|
2015-08-29 16:20:18 -04:00
|
|
|
|
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
|
|
|
|
|
expression, and ``'!a'`` calls ``ascii()`` on the expression. These
|
2015-09-19 11:24:19 -04:00
|
|
|
|
conversions are applied before the call to ``format()``. The only
|
2015-08-29 16:20:18 -04:00
|
|
|
|
reason to use ``'!s'`` is if you want to specify a format specifier
|
|
|
|
|
that applies to ``str``, not to the type of the expression.
|
|
|
|
|
|
2017-12-15 17:07:55 -05:00
|
|
|
|
F-strings use the same format specifier mini-language as ``str.format``.
|
2015-08-29 16:20:18 -04:00
|
|
|
|
Similar to ``str.format()``, optional format specifiers maybe be
|
|
|
|
|
included inside the f-string, separated from the expression (or the
|
|
|
|
|
type conversion, if specified) by a colon. If a format specifier is
|
2015-09-05 13:50:27 -04:00
|
|
|
|
not provided, an empty string is used.
|
2015-08-07 21:33:01 -04:00
|
|
|
|
|
|
|
|
|
So, an f-string looks like::
|
|
|
|
|
|
2015-09-12 20:08:18 -04:00
|
|
|
|
f ' <text> { <expression> <optional !s, !r, or !a> <optional : format specifier> } <text> ... '
|
2015-08-07 21:33:01 -04:00
|
|
|
|
|
2015-09-19 11:24:19 -04:00
|
|
|
|
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.
|
2015-08-07 21:33:01 -04:00
|
|
|
|
|
2016-11-06 11:18:17 -05:00
|
|
|
|
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.
|
|
|
|
|
|
2015-08-29 16:20:18 -04:00
|
|
|
|
Expressions cannot contain ``':'`` or ``'!'`` outside of strings or
|
2015-09-05 13:50:27 -04:00
|
|
|
|
parentheses, brackets, or braces. The exception is that the ``'!='``
|
2015-08-29 16:20:18 -04:00
|
|
|
|
operator is allowed as a special case.
|
2015-08-07 21:33:01 -04:00
|
|
|
|
|
2015-08-28 14:26:58 -04:00
|
|
|
|
Escape sequences
|
|
|
|
|
----------------
|
|
|
|
|
|
2016-11-06 11:18:17 -05:00
|
|
|
|
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'{\'quoted string\'}'
|
|
|
|
|
File "<stdin>", line 1
|
|
|
|
|
SyntaxError: f-string expression part cannot include a backslash
|
2015-08-28 14:26:58 -04:00
|
|
|
|
|
2016-11-06 11:18:17 -05:00
|
|
|
|
You can use a different type of quote inside the expression::
|
2015-08-28 14:26:58 -04:00
|
|
|
|
|
2016-11-06 11:18:17 -05:00
|
|
|
|
>>> f'{"quoted string"}'
|
|
|
|
|
'quoted string'
|
|
|
|
|
|
|
|
|
|
Backslash escapes may appear inside the string portions of an
|
|
|
|
|
f-string.
|
2015-08-28 14:26:58 -04:00
|
|
|
|
|
2015-09-04 20:28:35 -04:00
|
|
|
|
Note that the correct way to have a literal brace appear in the
|
|
|
|
|
resulting string value is to double the brace::
|
|
|
|
|
|
|
|
|
|
>>> f'{{ {4*10} }}'
|
|
|
|
|
'{ 40 }'
|
|
|
|
|
>>> f'{{{4*10}}}'
|
|
|
|
|
'{40}'
|
|
|
|
|
|
2016-08-18 12:59:00 -04:00
|
|
|
|
Like all raw strings in Python, no escape processing is done for raw
|
2015-09-08 20:10:44 -04:00
|
|
|
|
f-strings::
|
|
|
|
|
|
|
|
|
|
>>> fr'x={4*10}\n'
|
|
|
|
|
'x=40\\n'
|
|
|
|
|
|
|
|
|
|
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
|
2016-11-06 11:18:17 -05:00
|
|
|
|
of correct ways to write this f-string: with a different quote
|
|
|
|
|
character::
|
2015-09-08 20:10:44 -04:00
|
|
|
|
|
|
|
|
|
f"abc {a['x']} def"
|
|
|
|
|
|
|
|
|
|
Or with triple quotes::
|
|
|
|
|
|
|
|
|
|
f'''abc {a['x']} def'''
|
|
|
|
|
|
2015-08-07 21:33:01 -04:00
|
|
|
|
Code equivalence
|
|
|
|
|
----------------
|
|
|
|
|
|
2015-08-24 14:35:44 -04:00
|
|
|
|
The exact code used to implement f-strings is not specified. However,
|
|
|
|
|
it is guaranteed that any embedded value that is converted to a string
|
2015-08-29 16:20:18 -04:00
|
|
|
|
will use that value's ``__format__`` method. This is the same
|
|
|
|
|
mechanism that ``str.format()`` uses to convert values to strings.
|
2015-08-07 21:33:01 -04:00
|
|
|
|
|
|
|
|
|
For example, this code::
|
|
|
|
|
|
2015-09-22 17:57:36 -04:00
|
|
|
|
f'abc{expr1:spec1}{expr2!r:spec2}def{expr3}ghi'
|
2015-08-07 21:33:01 -04:00
|
|
|
|
|
2016-05-03 05:03:16 -04:00
|
|
|
|
Might be evaluated as::
|
2015-08-07 21:33:01 -04:00
|
|
|
|
|
2015-09-22 17:57:36 -04:00
|
|
|
|
'abc' + format(expr1, spec1) + format(repr(expr2), spec2) + 'def' + format(expr3) + 'ghi'
|
2015-08-07 21:33:01 -04:00
|
|
|
|
|
|
|
|
|
Expression evaluation
|
|
|
|
|
---------------------
|
|
|
|
|
|
|
|
|
|
The expressions that are extracted from the string are evaluated in
|
|
|
|
|
the context where the f-string appeared. This means the expression has
|
|
|
|
|
full access to local and global variables. Any valid Python expression
|
|
|
|
|
can be used, including function and method calls.
|
|
|
|
|
|
|
|
|
|
Because the f-strings are evaluated where the string appears in the
|
|
|
|
|
source code, there is no additional expressiveness available with
|
|
|
|
|
f-strings. There are also no additional security concerns: you could
|
|
|
|
|
have also just written the same expression, not inside of an
|
|
|
|
|
f-string::
|
|
|
|
|
|
|
|
|
|
>>> def foo():
|
|
|
|
|
... return 20
|
|
|
|
|
...
|
|
|
|
|
>>> f'result={foo()}'
|
|
|
|
|
'result=20'
|
|
|
|
|
|
|
|
|
|
Is equivalent to::
|
|
|
|
|
|
|
|
|
|
>>> 'result=' + str(foo())
|
|
|
|
|
'result=20'
|
|
|
|
|
|
2015-09-04 17:09:56 -04:00
|
|
|
|
Expressions are parsed with the equivalent of ``ast.parse('(' +
|
|
|
|
|
expression + ')', '<fstring>', 'eval')`` [#]_.
|
|
|
|
|
|
|
|
|
|
Note that since the expression is enclosed by implicit parentheses
|
|
|
|
|
before evaluation, expressions can contain newlines. For example::
|
2015-08-20 21:14:43 -04:00
|
|
|
|
|
|
|
|
|
>>> x = 0
|
|
|
|
|
>>> f'''{x
|
|
|
|
|
... +1}'''
|
2015-09-04 17:09:56 -04:00
|
|
|
|
'1'
|
2015-08-20 21:14:43 -04:00
|
|
|
|
|
2015-09-04 17:09:56 -04:00
|
|
|
|
>>> d = {0: 'zero'}
|
|
|
|
|
>>> f'''{d[0
|
|
|
|
|
... ]}'''
|
|
|
|
|
'zero'
|
2015-08-20 21:14:43 -04:00
|
|
|
|
|
2015-08-07 21:33:01 -04:00
|
|
|
|
Format specifiers
|
|
|
|
|
-----------------
|
|
|
|
|
|
2015-08-10 09:17:36 -04:00
|
|
|
|
Format specifiers may also contain evaluated expressions. This allows
|
|
|
|
|
code such as::
|
|
|
|
|
|
|
|
|
|
>>> width = 10
|
|
|
|
|
>>> precision = 4
|
|
|
|
|
>>> value = decimal.Decimal('12.34567')
|
2015-08-24 08:00:49 -04:00
|
|
|
|
>>> f'result: {value:{width}.{precision}}'
|
2015-08-10 09:17:36 -04:00
|
|
|
|
'result: 12.35'
|
|
|
|
|
|
|
|
|
|
Once expressions in a format specifier are evaluated (if necessary),
|
2015-08-29 16:20:18 -04:00
|
|
|
|
format specifiers are not interpreted by the f-string evaluator. Just
|
|
|
|
|
as in ``str.format()``, they are merely passed in to the
|
|
|
|
|
``__format__()`` method of the object being formatted.
|
2015-08-07 21:33:01 -04:00
|
|
|
|
|
|
|
|
|
Concatenating strings
|
|
|
|
|
---------------------
|
|
|
|
|
|
|
|
|
|
Adjacent f-strings and regular strings are concatenated. Regular
|
|
|
|
|
strings are concatenated at compile time, and f-strings are
|
|
|
|
|
concatenated at run time. For example, the expression::
|
|
|
|
|
|
|
|
|
|
>>> x = 10
|
|
|
|
|
>>> y = 'hi'
|
2015-08-20 21:14:43 -04:00
|
|
|
|
>>> 'a' 'b' f'{x}' '{c}' f'str<{y:^4}>' 'd' 'e'
|
2015-08-07 21:33:01 -04:00
|
|
|
|
|
|
|
|
|
yields the value::
|
|
|
|
|
|
2015-08-20 21:14:43 -04:00
|
|
|
|
'ab10{c}str< hi >de'
|
2015-08-07 21:33:01 -04:00
|
|
|
|
|
2015-08-20 20:55:54 -04:00
|
|
|
|
While the exact method of this run time concatenation is unspecified,
|
2015-08-20 20:02:45 -04:00
|
|
|
|
the above code might evaluate to::
|
2015-08-07 21:33:01 -04:00
|
|
|
|
|
2015-09-19 11:24:19 -04:00
|
|
|
|
'ab' + format(x) + '{c}' + 'str<' + format(y, '^4') + '>de'
|
2015-08-20 20:55:54 -04:00
|
|
|
|
|
2015-09-12 06:55:44 -04:00
|
|
|
|
Each f-string is entirely evaluated before being concatenated to
|
|
|
|
|
adjacent f-strings. That means that this::
|
|
|
|
|
|
|
|
|
|
>>> f'{x' f'}'
|
|
|
|
|
|
|
|
|
|
Is a syntax error, because the first f-string does not contain a
|
|
|
|
|
closing brace.
|
|
|
|
|
|
2015-08-07 21:33:01 -04:00
|
|
|
|
Error handling
|
|
|
|
|
--------------
|
|
|
|
|
|
|
|
|
|
Either compile time or run time errors can occur when processing
|
|
|
|
|
f-strings. Compile time errors are limited to those errors that can be
|
|
|
|
|
detected when scanning an f-string. These errors all raise
|
2015-08-29 16:20:18 -04:00
|
|
|
|
``SyntaxError``.
|
2015-08-07 21:33:01 -04:00
|
|
|
|
|
|
|
|
|
Unmatched braces::
|
|
|
|
|
|
|
|
|
|
>>> f'x={x'
|
|
|
|
|
File "<stdin>", line 1
|
2015-09-24 08:54:17 -04:00
|
|
|
|
SyntaxError: f-string: expecting '}'
|
2015-08-07 21:33:01 -04:00
|
|
|
|
|
|
|
|
|
Invalid expressions::
|
|
|
|
|
|
|
|
|
|
>>> f'x={!x}'
|
2015-09-24 08:54:17 -04:00
|
|
|
|
File "<stdin>", line 1
|
|
|
|
|
SyntaxError: f-string: empty expression not allowed
|
2015-08-07 21:33:01 -04:00
|
|
|
|
|
|
|
|
|
Run time errors occur when evaluating the expressions inside an
|
2015-08-07 22:25:27 -04:00
|
|
|
|
f-string. Note that an f-string can be evaluated multiple times, and
|
|
|
|
|
work sometimes and raise an error at other times::
|
2015-08-07 21:33:01 -04:00
|
|
|
|
|
|
|
|
|
>>> d = {0:10, 1:20}
|
|
|
|
|
>>> for i in range(3):
|
|
|
|
|
... print(f'{i}:{d[i]}')
|
|
|
|
|
...
|
|
|
|
|
0:10
|
|
|
|
|
1:20
|
|
|
|
|
Traceback (most recent call last):
|
|
|
|
|
File "<stdin>", line 2, in <module>
|
|
|
|
|
KeyError: 2
|
|
|
|
|
|
2015-08-07 22:25:27 -04:00
|
|
|
|
or::
|
|
|
|
|
|
|
|
|
|
>>> for x in (32, 100, 'fifty'):
|
2015-08-08 02:48:16 -04:00
|
|
|
|
... print(f'x = {x:+3}')
|
2015-08-07 22:25:27 -04:00
|
|
|
|
...
|
|
|
|
|
'x = +32'
|
|
|
|
|
'x = +100'
|
|
|
|
|
Traceback (most recent call last):
|
|
|
|
|
File "<stdin>", line 2, in <module>
|
|
|
|
|
ValueError: Sign not allowed in string format specifier
|
|
|
|
|
|
2015-09-04 17:09:56 -04:00
|
|
|
|
Leading and trailing whitespace in expressions is ignored
|
2015-08-20 20:02:45 -04:00
|
|
|
|
---------------------------------------------------------
|
2015-08-07 21:33:01 -04:00
|
|
|
|
|
2015-08-20 20:02:45 -04:00
|
|
|
|
For ease of readability, leading and trailing whitespace in
|
2015-09-12 20:08:18 -04:00
|
|
|
|
expressions is ignored. This is a by-product of enclosing the
|
|
|
|
|
expression in parentheses before evaluation.
|
2015-08-07 21:33:01 -04:00
|
|
|
|
|
2015-08-28 12:21:04 -04:00
|
|
|
|
Evaluation order of expressions
|
|
|
|
|
-------------------------------
|
|
|
|
|
|
|
|
|
|
The expressions in an f-string are evaluated in left-to-right
|
|
|
|
|
order. This is detectable only if the expressions have side effects::
|
|
|
|
|
|
|
|
|
|
>>> def fn(l, incr):
|
|
|
|
|
... result = l[0]
|
|
|
|
|
... l[0] += incr
|
|
|
|
|
... return result
|
|
|
|
|
...
|
|
|
|
|
>>> lst = [0]
|
|
|
|
|
>>> f'{fn(lst,2)} {fn(lst,3)}'
|
|
|
|
|
'0 2'
|
|
|
|
|
>>> f'{fn(lst,2)} {fn(lst,3)}'
|
|
|
|
|
'5 7'
|
|
|
|
|
>>> lst
|
|
|
|
|
[10]
|
|
|
|
|
|
2015-08-07 21:33:01 -04:00
|
|
|
|
Discussion
|
|
|
|
|
==========
|
|
|
|
|
|
2015-08-21 18:35:55 -04:00
|
|
|
|
python-ideas discussion
|
|
|
|
|
-----------------------
|
2015-08-07 21:33:01 -04:00
|
|
|
|
|
2015-08-21 18:35:55 -04:00
|
|
|
|
Most of the discussions on python-ideas [#]_ focused on three issues:
|
|
|
|
|
|
2016-05-03 04:18:02 -04:00
|
|
|
|
- How to denote f-strings,
|
|
|
|
|
- How to specify the location of expressions in f-strings, and
|
|
|
|
|
- Whether to allow full Python expressions.
|
2015-08-07 21:33:01 -04:00
|
|
|
|
|
2015-08-21 18:35:55 -04:00
|
|
|
|
How to denote f-strings
|
|
|
|
|
***********************
|
|
|
|
|
|
|
|
|
|
Because the compiler must be involved in evaluating the expressions
|
|
|
|
|
contained in the interpolated strings, there must be some way to
|
|
|
|
|
denote to the compiler which strings should be evaluated. This PEP
|
2015-09-05 13:50:27 -04:00
|
|
|
|
chose a leading ``'f'`` character preceding the string literal. This
|
2015-08-29 16:20:18 -04:00
|
|
|
|
is similar to how ``'b'`` and ``'r'`` prefixes change the meaning of
|
|
|
|
|
the string itself, at compile time. Other prefixes were suggested,
|
|
|
|
|
such as ``'i'``. No option seemed better than the other, so ``'f'``
|
|
|
|
|
was chosen.
|
2015-08-21 18:35:55 -04:00
|
|
|
|
|
|
|
|
|
Another option was to support special functions, known to the
|
2015-08-29 16:20:18 -04:00
|
|
|
|
compiler, such as ``Format()``. This seems like too much magic for
|
|
|
|
|
Python: not only is there a chance for collision with existing
|
|
|
|
|
identifiers, the PEP author feels that it's better to signify the
|
|
|
|
|
magic with a string prefix character.
|
2015-08-21 18:35:55 -04:00
|
|
|
|
|
|
|
|
|
How to specify the location of expressions in f-strings
|
|
|
|
|
*******************************************************
|
|
|
|
|
|
2015-08-29 16:20:18 -04:00
|
|
|
|
This PEP supports the same syntax as ``str.format()`` for
|
|
|
|
|
distinguishing replacement text inside strings: expressions are
|
|
|
|
|
contained inside braces. There were other options suggested, such as
|
|
|
|
|
``string.Template``'s ``$identifier`` or ``${expression}``.
|
2015-08-21 18:35:55 -04:00
|
|
|
|
|
2015-08-29 16:20:18 -04:00
|
|
|
|
While ``$identifier`` is no doubt more familiar to shell scripters and
|
|
|
|
|
users of some other languages, in Python ``str.format()`` is heavily
|
2015-08-21 18:35:55 -04:00
|
|
|
|
used. A quick search of Python's standard library shows only a handful
|
2015-08-29 16:20:18 -04:00
|
|
|
|
of uses of ``string.Template``, but hundreds of uses of
|
|
|
|
|
``str.format()``.
|
2015-08-21 18:35:55 -04:00
|
|
|
|
|
|
|
|
|
Another proposed alternative was to have the substituted text between
|
2015-09-04 21:25:59 -04:00
|
|
|
|
``\{`` and ``}`` or between ``\{`` and ``\}``. While this syntax would
|
|
|
|
|
probably be desirable if all string literals were to support
|
2015-08-29 16:20:18 -04:00
|
|
|
|
interpolation, this PEP only supports strings that are already marked
|
|
|
|
|
with the leading ``'f'``. As such, the PEP is using unadorned braces
|
|
|
|
|
to denoted substituted text, in order to leverage end user familiarity
|
|
|
|
|
with ``str.format()``.
|
2015-08-21 18:35:55 -04:00
|
|
|
|
|
|
|
|
|
Supporting full Python expressions
|
|
|
|
|
**********************************
|
|
|
|
|
|
|
|
|
|
Many people on the python-ideas discussion wanted support for either
|
|
|
|
|
only single identifiers, or a limited subset of Python expressions
|
2015-08-29 16:20:18 -04:00
|
|
|
|
(such as the subset supported by ``str.format()``). This PEP supports
|
|
|
|
|
full Python expressions inside the braces. Without full expressions,
|
|
|
|
|
some desirable usage would be cumbersome. For example::
|
2015-08-21 18:35:55 -04:00
|
|
|
|
|
|
|
|
|
>>> f'Column={col_idx+1}'
|
|
|
|
|
>>> f'number of items: {len(items)}'
|
|
|
|
|
|
|
|
|
|
would become::
|
|
|
|
|
|
|
|
|
|
>>> col_number = col_idx+1
|
|
|
|
|
>>> f'Column={col_number}'
|
|
|
|
|
>>> n_items = len(items)
|
|
|
|
|
>>> f'number of items: {n_items}'
|
|
|
|
|
|
|
|
|
|
While it's true that very ugly expressions could be included in the
|
|
|
|
|
f-strings, this PEP takes the position that such uses should be
|
|
|
|
|
addressed in a linter or code review::
|
|
|
|
|
|
2015-09-04 21:25:59 -04:00
|
|
|
|
>>> f'mapping is { {a:b for (a, b) in ((1, 2), (3, 4))} }'
|
2015-08-21 18:35:55 -04:00
|
|
|
|
'mapping is {1: 2, 3: 4}'
|
2015-08-07 21:33:01 -04:00
|
|
|
|
|
2015-08-08 10:07:40 -04:00
|
|
|
|
Similar support in other languages
|
|
|
|
|
----------------------------------
|
|
|
|
|
|
2015-08-20 20:02:45 -04:00
|
|
|
|
Wikipedia has a good discussion of string interpolation in other
|
|
|
|
|
programming languages [#]_. This feature is implemented in many
|
|
|
|
|
languages, with a variety of syntaxes and restrictions.
|
2015-08-08 10:07:40 -04:00
|
|
|
|
|
2015-08-07 21:33:01 -04:00
|
|
|
|
Differences between f-string and str.format expressions
|
|
|
|
|
-------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
There is one small difference between the limited expressions allowed
|
2015-08-29 16:20:18 -04:00
|
|
|
|
in ``str.format()`` and the full expressions allowed inside
|
|
|
|
|
f-strings. The difference is in how index lookups are performed. In
|
|
|
|
|
``str.format()``, index values that do not look like numbers are
|
|
|
|
|
converted to strings::
|
2015-08-07 21:33:01 -04:00
|
|
|
|
|
|
|
|
|
>>> d = {'a': 10, 'b': 20}
|
|
|
|
|
>>> 'a={d[a]}'.format(d=d)
|
|
|
|
|
'a=10'
|
|
|
|
|
|
2015-08-29 16:20:18 -04:00
|
|
|
|
Notice that the index value is converted to the string ``'a'`` when it
|
|
|
|
|
is looked up in the dict.
|
2015-08-07 21:33:01 -04:00
|
|
|
|
|
|
|
|
|
However, in f-strings, you would need to use a literal for the value
|
2015-08-29 16:20:18 -04:00
|
|
|
|
of ``'a'``::
|
2015-08-07 21:33:01 -04:00
|
|
|
|
|
|
|
|
|
>>> f'a={d["a"]}'
|
|
|
|
|
'a=10'
|
|
|
|
|
|
|
|
|
|
This difference is required because otherwise you would not be able to
|
|
|
|
|
use variables as index values::
|
|
|
|
|
|
|
|
|
|
>>> a = 'b'
|
|
|
|
|
>>> f'a={d[a]}'
|
|
|
|
|
'a=20'
|
|
|
|
|
|
2015-08-28 11:41:58 -04:00
|
|
|
|
See [#]_ for a further discussion. It was this observation that led to
|
|
|
|
|
full Python expressions being supported in f-strings.
|
|
|
|
|
|
2015-08-29 16:20:18 -04:00
|
|
|
|
Furthermore, the limited expressions that ``str.format()`` understands
|
2015-08-27 10:20:59 -04:00
|
|
|
|
need not be valid Python expressions. For example::
|
|
|
|
|
|
|
|
|
|
>>> '{i[";]}'.format(i={'";':4})
|
|
|
|
|
'4'
|
|
|
|
|
|
|
|
|
|
For this reason, the str.format() "expression parser" is not suitable
|
|
|
|
|
for use when implementing f-strings.
|
|
|
|
|
|
2015-08-20 20:02:45 -04:00
|
|
|
|
Triple-quoted f-strings
|
|
|
|
|
-----------------------
|
|
|
|
|
|
|
|
|
|
Triple quoted f-strings are allowed. These strings are parsed just as
|
2015-09-04 21:25:59 -04:00
|
|
|
|
normal triple-quoted strings are. After parsing and decoding, the
|
2015-09-12 20:08:18 -04:00
|
|
|
|
normal f-string logic is applied, and ``__format__()`` is called on
|
|
|
|
|
each value.
|
2015-08-20 20:02:45 -04:00
|
|
|
|
|
|
|
|
|
Raw f-strings
|
|
|
|
|
-------------
|
|
|
|
|
|
2016-07-11 11:14:08 -04:00
|
|
|
|
Raw and f-strings may be combined. For example, they could be used to
|
2015-08-20 20:02:45 -04:00
|
|
|
|
build up regular expressions::
|
|
|
|
|
|
|
|
|
|
>>> header = 'Subject'
|
|
|
|
|
>>> fr'{header}:\s+'
|
|
|
|
|
'Subject:\\s+'
|
|
|
|
|
|
|
|
|
|
In addition, raw f-strings may be combined with triple-quoted strings.
|
|
|
|
|
|
2015-08-07 21:33:01 -04:00
|
|
|
|
No binary f-strings
|
|
|
|
|
-------------------
|
|
|
|
|
|
2015-08-29 16:20:18 -04:00
|
|
|
|
For the same reason that we don't support ``bytes.format()``, you may
|
|
|
|
|
not combine ``'f'`` with ``'b'`` string literals. The primary problem
|
|
|
|
|
is that an object's ``__format__()`` method may return Unicode data that
|
|
|
|
|
is not compatible with a bytes string.
|
2015-08-07 21:33:01 -04:00
|
|
|
|
|
2015-08-21 04:54:23 -04:00
|
|
|
|
Binary f-strings would first require a solution for
|
2015-08-29 16:20:18 -04:00
|
|
|
|
``bytes.format()``. This idea has been proposed in the past, most
|
|
|
|
|
recently in PEP 461 [#]_. The discussions of such a feature usually
|
|
|
|
|
suggest either
|
2015-08-21 04:54:23 -04:00
|
|
|
|
|
2016-05-03 04:35:10 -04:00
|
|
|
|
- adding a method such as ``__bformat__()`` so an object can control
|
|
|
|
|
how it is converted to bytes, or
|
2015-08-21 04:54:23 -04:00
|
|
|
|
|
2016-05-03 04:35:10 -04:00
|
|
|
|
- having ``bytes.format()`` not be as general purpose or extensible
|
|
|
|
|
as ``str.format()``.
|
2015-08-21 04:54:23 -04:00
|
|
|
|
|
|
|
|
|
Both of these remain as options in the future, if such functionality
|
|
|
|
|
is desired.
|
2015-08-20 20:02:45 -04:00
|
|
|
|
|
2015-08-29 16:20:18 -04:00
|
|
|
|
``!s``, ``!r``, and ``!a`` are redundant
|
|
|
|
|
----------------------------------------
|
2015-08-07 21:33:01 -04:00
|
|
|
|
|
2015-08-29 16:21:04 -04:00
|
|
|
|
The ``!s``, ``!r``, and ``!a`` conversions are not strictly
|
|
|
|
|
required. Because arbitrary expressions are allowed inside the
|
|
|
|
|
f-strings, this code::
|
2015-08-07 21:33:01 -04:00
|
|
|
|
|
|
|
|
|
>>> a = 'some string'
|
|
|
|
|
>>> f'{a!r}'
|
|
|
|
|
"'some string'"
|
|
|
|
|
|
|
|
|
|
Is identical to::
|
|
|
|
|
|
|
|
|
|
>>> f'{repr(a)}'
|
|
|
|
|
"'some string'"
|
|
|
|
|
|
2015-08-29 16:20:18 -04:00
|
|
|
|
Similarly, ``!s`` can be replaced by calls to ``str()`` and ``!a`` by
|
|
|
|
|
calls to ``ascii()``.
|
2015-08-07 21:33:01 -04:00
|
|
|
|
|
2015-08-29 16:20:18 -04:00
|
|
|
|
However, ``!s``, ``!r``, and ``!a`` are supported by this PEP in order
|
|
|
|
|
to minimize the differences with ``str.format()``. ``!s``, ``!r``, and
|
|
|
|
|
``!a`` are required in ``str.format()`` because it does not allow the
|
|
|
|
|
execution of arbitrary expressions.
|
2015-08-07 21:33:01 -04:00
|
|
|
|
|
|
|
|
|
Lambdas inside expressions
|
|
|
|
|
--------------------------
|
|
|
|
|
|
2015-08-29 16:20:18 -04:00
|
|
|
|
Because lambdas use the ``':'`` character, they cannot appear outside
|
2017-07-12 14:58:51 -04:00
|
|
|
|
of parentheses in an expression. The colon is interpreted as the start
|
2015-08-29 16:20:18 -04:00
|
|
|
|
of the format specifier, which means the start of the lambda
|
|
|
|
|
expression is seen and is syntactically invalid. As there's no
|
|
|
|
|
practical use for a plain lambda in an f-string expression, this is
|
|
|
|
|
not seen as much of a limitation.
|
2015-08-07 21:33:01 -04:00
|
|
|
|
|
2015-09-05 13:50:27 -04:00
|
|
|
|
If you feel you must use lambdas, they may be used inside of parentheses::
|
2015-08-07 21:33:01 -04:00
|
|
|
|
|
|
|
|
|
>>> f'{(lambda x: x*2)(3)}'
|
|
|
|
|
'6'
|
|
|
|
|
|
2015-09-12 11:59:53 -04:00
|
|
|
|
Can't combine with 'u'
|
|
|
|
|
--------------------------
|
|
|
|
|
|
|
|
|
|
The 'u' prefix was added to Python 3.3 in PEP 414 as a means to ease
|
|
|
|
|
source compatibility with Python 2.7. Because Python 2.7 will never
|
|
|
|
|
support f-strings, there is nothing to be gained by being able to
|
|
|
|
|
combine the 'f' prefix with 'u'.
|
|
|
|
|
|
2015-08-24 15:49:18 -04:00
|
|
|
|
Examples from Python's source code
|
|
|
|
|
==================================
|
|
|
|
|
|
|
|
|
|
Here are some examples from Python source code that currently use
|
2015-08-29 16:20:18 -04:00
|
|
|
|
``str.format()``, and how they would look with f-strings. This PEP
|
|
|
|
|
does not recommend wholesale converting to f-strings, these are just
|
|
|
|
|
examples of real-world usages of ``str.format()`` and how they'd look
|
|
|
|
|
if written from scratch using f-strings.
|
2015-08-24 15:49:18 -04:00
|
|
|
|
|
2015-08-29 16:20:18 -04:00
|
|
|
|
``Lib/asyncio/locks.py``::
|
2015-08-24 15:49:18 -04:00
|
|
|
|
|
|
|
|
|
extra = '{},waiters:{}'.format(extra, len(self._waiters))
|
|
|
|
|
extra = f'{extra},waiters:{len(self._waiters)}'
|
|
|
|
|
|
2015-08-29 16:20:18 -04:00
|
|
|
|
``Lib/configparser.py``::
|
2015-08-24 15:49:18 -04:00
|
|
|
|
|
|
|
|
|
message.append(" [line {0:2d}]".format(lineno))
|
|
|
|
|
message.append(f" [line {lineno:2d}]")
|
|
|
|
|
|
2015-08-29 16:20:18 -04:00
|
|
|
|
``Tools/clinic/clinic.py``::
|
2015-08-24 15:49:18 -04:00
|
|
|
|
|
|
|
|
|
methoddef_name = "{}_METHODDEF".format(c_basename.upper())
|
|
|
|
|
methoddef_name = f"{c_basename.upper()}_METHODDEF"
|
|
|
|
|
|
2015-08-29 16:20:18 -04:00
|
|
|
|
``python-config.py``::
|
2015-08-24 15:49:18 -04:00
|
|
|
|
|
|
|
|
|
print("Usage: {0} [{1}]".format(sys.argv[0], '|'.join('--'+opt for opt in valid_opts)), file=sys.stderr)
|
|
|
|
|
print(f"Usage: {sys.argv[0]} [{'|'.join('--'+opt for opt in valid_opts)}]", file=sys.stderr)
|
|
|
|
|
|
2015-08-21 18:38:38 -04:00
|
|
|
|
References
|
|
|
|
|
==========
|
2015-08-07 21:33:01 -04:00
|
|
|
|
|
|
|
|
|
.. [#] %-formatting
|
|
|
|
|
(https://docs.python.org/3/library/stdtypes.html#printf-style-string-formatting)
|
|
|
|
|
|
|
|
|
|
.. [#] str.format
|
|
|
|
|
(https://docs.python.org/3/library/string.html#formatstrings)
|
|
|
|
|
|
|
|
|
|
.. [#] string.Template documentation
|
|
|
|
|
(https://docs.python.org/3/library/string.html#template-strings)
|
|
|
|
|
|
|
|
|
|
.. [#] Formatting using locals() and globals()
|
|
|
|
|
(https://mail.python.org/pipermail/python-ideas/2015-July/034671.html)
|
|
|
|
|
|
|
|
|
|
.. [#] Avoid locals() and globals()
|
|
|
|
|
(https://mail.python.org/pipermail/python-ideas/2015-July/034701.html)
|
|
|
|
|
|
2015-09-04 20:28:35 -04:00
|
|
|
|
.. [#] String literal description
|
|
|
|
|
(https://docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals)
|
|
|
|
|
|
2015-08-20 21:14:43 -04:00
|
|
|
|
.. [#] ast.parse() documentation
|
|
|
|
|
(https://docs.python.org/3/library/ast.html#ast.parse)
|
|
|
|
|
|
2015-08-07 21:33:01 -04:00
|
|
|
|
.. [#] Start of python-ideas discussion
|
|
|
|
|
(https://mail.python.org/pipermail/python-ideas/2015-July/034657.html)
|
|
|
|
|
|
2015-08-20 20:27:23 -04:00
|
|
|
|
.. [#] Wikipedia article on string interpolation
|
|
|
|
|
(https://en.wikipedia.org/wiki/String_interpolation)
|
|
|
|
|
|
2015-08-07 21:33:01 -04:00
|
|
|
|
.. [#] Differences in str.format() and f-string expressions
|
|
|
|
|
(https://mail.python.org/pipermail/python-ideas/2015-July/034726.html)
|
|
|
|
|
|
2015-08-21 04:57:04 -04:00
|
|
|
|
.. [#] PEP 461 rejects bytes.format()
|
|
|
|
|
(https://www.python.org/dev/peps/pep-0461/#proposed-variations)
|
2015-08-21 04:54:23 -04:00
|
|
|
|
|
2015-08-07 21:33:01 -04:00
|
|
|
|
Copyright
|
|
|
|
|
=========
|
|
|
|
|
|
|
|
|
|
This document has been placed in the public domain.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
..
|
|
|
|
|
Local Variables:
|
|
|
|
|
mode: indented-text
|
|
|
|
|
indent-tabs-mode: nil
|
|
|
|
|
sentence-end-double-space: t
|
|
|
|
|
fill-column: 70
|
|
|
|
|
coding: utf-8
|
|
|
|
|
End:
|