Flushed out more text. Other than removing !s, !r, and !a, I think I am mostly done.
This commit is contained in:
parent
1d6b74f376
commit
29a1f236da
157
pep-0498.txt
157
pep-0498.txt
|
@ -25,12 +25,12 @@ strings.
|
||||||
This PEP does not propose to remove or deprecate any of the existing
|
This PEP does not propose to remove or deprecate any of the existing
|
||||||
string formatting mechanisms.
|
string formatting mechanisms.
|
||||||
|
|
||||||
f-strings provide a way to combine string literals with Python
|
f-strings provide a way to embed expressions inside string literals,
|
||||||
expressions, using a minimal syntax. It should be noted that an
|
using a minimal syntax. It should be noted that an f-string is really
|
||||||
f-string is really an expression evaluated at run time, not a constant
|
an expression evaluated at run time, not a constant value. In Python
|
||||||
value. An f-string is a string, prefixed with 'f', that contains
|
source code, an f-string is a literal string, prefixed with 'f', that
|
||||||
expressions inside braces. The expressions are replaced with their
|
contains expressions inside braces. The expressions are replaced with
|
||||||
values. Some examples are::
|
their values. Some examples are::
|
||||||
|
|
||||||
>>> import datetime
|
>>> import datetime
|
||||||
>>> name = 'Fred'
|
>>> name = 'Fred'
|
||||||
|
@ -110,11 +110,11 @@ inside strings.
|
||||||
|
|
||||||
In this sense, string.Template and %-formatting have similar
|
In this sense, string.Template and %-formatting have similar
|
||||||
shortcomings to str.format(), but also support fewer formatting
|
shortcomings to str.format(), but also support fewer formatting
|
||||||
options. In particular, they do not support __format__, so that there
|
options. In particular, they do not support the __format__ protocol,
|
||||||
is no way to control how a specific object is converted to a string,
|
so that there is no way to control how a specific object is converted
|
||||||
nor can it be extended to additional types that want to control how
|
to a string, nor can it be extended to additional types that want to
|
||||||
they are converted to strings (such as Decimal and datetime). This
|
control how they are converted to strings (such as Decimal and
|
||||||
example is not possible with string.Template::
|
datetime). This example is not possible with string.Template::
|
||||||
|
|
||||||
>>> value = 1234
|
>>> value = 1234
|
||||||
>>> f'input={value:#0.6x}'
|
>>> f'input={value:#0.6x}'
|
||||||
|
@ -164,6 +164,11 @@ leak. A called routine that has access to the callers locals() or
|
||||||
globals() has access to far more information than needed to do the
|
globals() has access to far more information than needed to do the
|
||||||
string interpolation.
|
string interpolation.
|
||||||
|
|
||||||
|
If locals() and globals() were used, and if a future extension to this
|
||||||
|
PEP would add an internationalization layer before str.interpolate()
|
||||||
|
is called, a malicious translator could get access to additional
|
||||||
|
variables in the callers context.
|
||||||
|
|
||||||
Guido stated [#]_ that any solution to better string interpolation
|
Guido stated [#]_ that any solution to better string interpolation
|
||||||
would not use locals() or globals().
|
would not use locals() or globals().
|
||||||
|
|
||||||
|
@ -214,20 +219,44 @@ special cased.
|
||||||
str.interpolate()
|
str.interpolate()
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
str.interpolate(mapping) will be a new method. It takes one argument:
|
str.interpolate(mapping) will be a new method on the str type. It
|
||||||
a mapping of field names to values. This method is the same as
|
takes one argument: a mapping of field names to values. This method is
|
||||||
str.format_map() [#]_, with one difference: it does not interpret the
|
the same as str.format_map() [#]_, with one difference: it does not
|
||||||
field_name [#]_ in any way. The field_name is only used to look up the
|
interpret the field_name [#]_ in any way. The field_name is only used
|
||||||
replacement value in the supplied mapping object. Like str.format()
|
to look up the replacement value in the supplied mapping object. Like
|
||||||
and str.format_map(), str.interpolate() does interpret and apply the
|
str.format() and str.format_map(), str.interpolate() does interpret
|
||||||
optional conversion and format_spec. Thus, a field_name may not
|
and apply the optional conversion and format_spec. Thus, a field_name
|
||||||
contain the characters ':' or '}', nor the strings '!s', '!r', or
|
may not contain the characters ':' or '}', nor the strings '!s', '!r',
|
||||||
'!a'.
|
or '!a'.
|
||||||
|
|
||||||
|
Examples::
|
||||||
|
|
||||||
|
>>> name = 'Guido'
|
||||||
|
>>> 'name={name}'.interpolate({'name': name})
|
||||||
|
'name=Guido'
|
||||||
|
|
||||||
|
>>> '{date} was on a {date:%A}. It was {weather}.'.interpolate({'weather': 'sunny', 'date': datetime.date(1991, 10, 12)})
|
||||||
|
'1991-10-12 was on a Saturday. It was sunny.'
|
||||||
|
|
||||||
|
Like str.format_map(), only the field_name portion inside braces is
|
||||||
|
used to look up values in the mapping. The format_spec is not used as
|
||||||
|
part of this lookup. Thus::
|
||||||
|
|
||||||
|
>>> 'name={name:10}'.interpolate({'name': name})
|
||||||
|
'name=Guido '
|
||||||
|
|
||||||
|
But::
|
||||||
|
|
||||||
|
>>> 'name={name:10}'.interpolate({'name:10': name})
|
||||||
|
'name=Guido '
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "<stdin>", line 1, in <module>
|
||||||
|
KeyError: 'name'
|
||||||
|
|
||||||
Code equivalence
|
Code equivalence
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
An f-string is evaluated at run time as a call to str.interpolate().
|
An f-string is evaluated at run time using a call to str.interpolate().
|
||||||
|
|
||||||
For example, this code::
|
For example, this code::
|
||||||
|
|
||||||
|
@ -401,13 +430,77 @@ This would be evaluated as::
|
||||||
Discussion
|
Discussion
|
||||||
==========
|
==========
|
||||||
|
|
||||||
Most of the discussions on python-ideas [#]_ focused on a few issues.
|
python-ideas discussion
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
Most of the discussions on python-ideas [#]_ focused on three issues:
|
||||||
|
|
||||||
|
- How to denote f-strings,
|
||||||
|
- How to specify the location of expressions in f-strings, and
|
||||||
- Whether to allow full Python expressions.
|
- Whether to allow full Python expressions.
|
||||||
- How to designate f-strings, and how to specify the location of
|
|
||||||
expressions in them.
|
|
||||||
|
|
||||||
XXX: more on the above issues.
|
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
|
||||||
|
chose a leading 'f' character preceeding the string literal. This 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.
|
||||||
|
|
||||||
|
Another option was to support special functions, known to the
|
||||||
|
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.
|
||||||
|
|
||||||
|
How to specify the location of expressions in f-strings
|
||||||
|
*******************************************************
|
||||||
|
|
||||||
|
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}.
|
||||||
|
|
||||||
|
While $identifier is no doubt more familiar to shell scripters and
|
||||||
|
users of some other languages, in Python str.format() is heavily
|
||||||
|
used. A quick search of Python's standard library shows only a handful
|
||||||
|
of uses of string.Template, but over 1000 uses of str.format().
|
||||||
|
|
||||||
|
Another proposed alternative was to have the substituted text between
|
||||||
|
\{ and } or between \{ and \}. While this syntax would probably be
|
||||||
|
desirable if all string literals were to support 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().
|
||||||
|
|
||||||
|
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
|
||||||
|
(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 forbidden::
|
||||||
|
|
||||||
|
>>> 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::
|
||||||
|
|
||||||
|
>>> f'mapping is { {a:b for (a, b) in ((1, 2), (3, 4))}}'
|
||||||
|
'mapping is {1: 2, 3: 4}'
|
||||||
|
|
||||||
Similar support in other languages
|
Similar support in other languages
|
||||||
----------------------------------
|
----------------------------------
|
||||||
|
@ -528,13 +621,13 @@ Lambdas may be used inside of parens::
|
||||||
Future extensions:
|
Future extensions:
|
||||||
==================
|
==================
|
||||||
|
|
||||||
XXX: By using another leading character (say, 'i'), we could extend
|
By using another leading character (say, 'i'), we could extend this
|
||||||
this proposal to cover internationalization and localization. The idea
|
proposal to cover internationalization and localization. The idea is
|
||||||
is that the string would be passed to some lookup function before
|
that the string would be passed to some lookup function before
|
||||||
.interpolate() is called on it::
|
.interpolate() is called on it::
|
||||||
|
|
||||||
>>> name = 'Eric'
|
>>> name = 'Eric'
|
||||||
>>> fi'Name: {name}'
|
>>> i'Name: {name}'
|
||||||
|
|
||||||
Could be translated as::
|
Could be translated as::
|
||||||
|
|
||||||
|
@ -551,8 +644,10 @@ field_names are not found in the mapping argument. The choices might
|
||||||
be: use the field_name, use a default (possibly empty) string, or
|
be: use the field_name, use a default (possibly empty) string, or
|
||||||
raise an exception.
|
raise an exception.
|
||||||
|
|
||||||
References
|
There would obviously need to be some way to specify to the compiler
|
||||||
==========
|
what lookup function would be called.
|
||||||
|
|
||||||
|
References ==========
|
||||||
|
|
||||||
.. [#] %-formatting
|
.. [#] %-formatting
|
||||||
(https://docs.python.org/3/library/stdtypes.html#printf-style-string-formatting)
|
(https://docs.python.org/3/library/stdtypes.html#printf-style-string-formatting)
|
||||||
|
|
Loading…
Reference in New Issue