In general, there's no way to start with a format specifier string and from it get the type of the object that it should be applied to. For example, any string without %'s is a valid datetime format specifier (of dubious value, but such is life). Perhaps a better example is decimal vs. float. What if I want %.2f to return a decimal? Would that just not be possible?

So I think you'd have to limit this to a small set of built-in types.

In general, I think overloading f-strings as assignment targets would be confusing. But I've been wrong before.

Eric

On 9/17/2020 12:52 AM, Dennis Sweeney wrote:
TL;DR: I propose the following behavior:

     >>> s = "She turned me into a newt."
     >>> f"She turned me into a {animal}." = s
     >>> animal
     'newt'

     >>> f"A {animal}?" = s
     Traceback (most recent call last):
     File "<pyshell#2>", line 1, in <module>
             f"A {animal}?" = s
     ValueError: f-string assignment target does not match 'She turned me into 
a newt.'

     >>> f"{hh:d}:{mm:d}:{ss:d}" = "11:59:59"
     >>> hh, mm, ss
     (11, 59, 59)

=== Rationale ===

Part of the reason I like f-strings so much is that they reduce the
cognitive overhead of reading code: they allow you to see *what* is
being inserted into a string in a way that also effortlessly shows
*where* in the string the value is being inserted. There is no need to
"paint-by-numbers" and remember which variable is {0} and which is {1}
in an unnecessary extra layer of indirection. F-strings allow string
formatting that is not only intelligible, but *locally* intelligible.

What I propose is the inverse feature, where you can assign a string
to an f-string, and the interpreter will maintain an invariant kept
in many other cases:

     >>> a[n] = 17
     >>> a[n] == 17
     True

     >>> obj.x = "foo"
     >>> obj.x == "foo"
     True

     # Proposed:
     >>> f"It is {hh}:{mm} {am_or_pm}" = "It is 11:45 PM"
     >>> f"It is {hh}:{mm} {am_or_pm}" == "It is 11:45 PM"
     True
     >>> hh
     '11'

This could be thought of as analogous to the c language's scanf
function, something I've always felt was just slightly lacking in
Python. I think such a feature would more clearly allow readers of
Python code to answer the question "What kinds of strings are allowed
here?". It would add certainty to programs that accept strings,
confirming early that the data you have is the data you want.
The code reads like a specification that beginners can understand in
a blink.


=== Existing way of achieving this ===

As of now, you could achieve the behavior with regular expressions:

     >>> import re
     >>> pattern = re.compile(r'It is (.+):(.+) (.+)')
     >>> match = pattern.fullmatch("It is 11:45 PM")
     >>> hh, mm, am_or_pm = match.groups()
     >>> hh
     '11'

But this suffers from the same paint-by-numbers, extra-indirection
issue that old-style string formatting runs into, an issue that
f-strings improve upon.

You could also do a strange mishmash of built-in str operations, like

     >>> s = "It is 11:45 PM"
     >>> empty, rest = s.split("It is ")
     >>> assert empty == ""
     >>> hh, rest = rest.split(":")
     >>> mm, am_or_pm = s.split(" ")
     >>> hh
     '11'

But this is 5 different lines to express one simple idea.
How many different times have you written a micro-parser like this?


=== Specification (open to bikeshedding) ===

In general, the goal would be to pursue the assignment-becomes-equal
invariant above. By default, assignment targets within f-strings would
be matched as strings. However, adding in a format specifier would
allow the matches to be evaluated as different data types, e.g.
f'{foo:d}' = "1" would make foo become the integer 1. If a more complex
format specifier was added that did not match anything that the
f-string could produce as an expression, then we'd still raise a
ValueError:

     >>> f"{x:.02f}" = "0.12345"
     Traceback (most recent call last):
     File "<pyshell#2>", line 1, in <module>
             f"{x:.02f}" = "0.12345"
     ValueError: f-string assignment target does not match '0.12345'

If we're feeling adventurous, one could turn the !r repr flag in a
match into an eval() of the matched string.

The f-string would match with the same eager semantics as regular
expressions, backtracking when a match is not made on the first
attempt.

Let me know what you think!
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/JEGSKODAK5MCO2HHUF4555JZPZ6SKNEC/
Code of Conduct: http://python.org/psf/codeofconduct/
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/HTPSJK77TLUFXMUY4XKHS6ES7F7H5UH7/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to