Should all strings become f-strings?
pyfound.blogspot.com
pyfound.blogspot.com
Admittedly this would be too big of a change to make now.
Likewise, "there should be only one way to do something". Now we have "%s"%somevalue, "".format(), and f"". I can't help but feel that .format() is the right option, being clear, flexible, explicit, and unambiguous.
I don't think thats a good idea.
description_string = "The {} is a problem, please look at: {}".format(
some_function(value)[lookup],
' '.join([item for item in list_of_items]),
)
Where, with f strings, you'd need to do some nasty escaping or create descriptive labels for the substitutions that were previously unnecessary.With the second option you also get the problem of a potential loss of cohesion as the variable 'name = some_function(value)[lookup]' won't be intrinsically tied to the string where it is being used and tends to float away from the string where it's actually being used. e.g.
name = some_function(value)[lookup]
[ 50 lines of code ]
description_string = f"{name} is a problem..." etc.
Which creates additional problems with readability, bugs, etc. >>> def some_function():
... return ['a','b','c']
...
>>> list_of_items = ['one','two','three']
>>> s = f"The {some_function()[1]} is a problem, please look at: {' '.join([item for item in list_of_items])}"
>>> s
'The b is a problem, please look at: one two three'
>>>
I'll admit that it's somewhat ugly, but there's no escaping needed. s = f"The {some_function()[1]} is a problem, please look at: {' '.join(list_of_items)}" s = f"The {some_function()["WHOOPS!!!"]} is a problem, please look at: {' '.join([item for item in functino_call("whoops again")])}"
This indirectly proves the point I think.No, with f-strings, you'd have to take the expressions you use in the call to format and stick them between the curly braces, and trade the .format(...) after the string for an f before it.
f-strings are almost without exception more terse than .format for single-use formatted strings.
If would be longer if you started attaching descriptive names to those expressions and using them in an f string.
aa = [
{"foo": "baz", "bar: "bam"},
{"foo": "blah", "bar": 1234},
]
for a in aa:
print("This is my message which says {foo} and {bar}".format(**a))Then it breaks.
And even that can be accommodated with f-here-strings.
This seems like an odd argument. PHP makes a clear distinction between string literals with single quotes and those with double quotes, where only double quotes do variable substitution and escape sequences. It's very common for PHP projects to default to single quotes and only use double quotes when their special handling is actually used.
* f"f-strings", which do both substitution and escaping
* regular "strings", which do escaping but no substitution
* r"r-strings" (for "raw"), which do neither
* b"b-strings", which are actually not strings but sequences of bytesThere are also the u"u-strings" which were reintroduced to reduce the workload when converting the Python 2 programs; unfortunately they forgot to do the same for the relatively common (at least when defining regular expressions) ru"ru-strings" and ur"ur-strings"...
But changing it in an existing language causes massive backward compatibility issues. Unlike the move from Python 2 to Python 3, it is trivial to build a perfect migration script (2to3 was useful but not perfect) -- it just needs to prefix "p" in front of all normal strings, or at least in front of all normal strings that contain the interpolation character(s).
But even so, the need to run that script is a VERY BIG DEAL. A perfect migration script doesn't help with sample code that is printed in a book, or thousands of other situations that are awkward to fix. It would, without a doubt, require very careful introduction by use of "from __future__ import". (The fact that Python has that facility is extremely helpful for this kind of migration.)
I am utterly bewildered by this article's claim that the proponent of this change thinks it should be dropped if it is to be introduced carefully using "from __future__ import". That is just stupid.
I would rather end up in a place where interpolation strings are the default, but it is not clear to me whether the path to get there is worth the pain.
I lived through the many "from __future__ import" of late Python 2.x releases, so I know I can deal with a "all_fstrings" solution during a migration period.
Looking through my code I see things like:
r"[a-zA-Z][a-zA-Z0-9]{3}"
which, if interpreted as an f-string, would change the regexp but not cause it to not compile - the breakage would be downstream.I suspect there's some places where existing code which uses .format() will still work, with all-f-strings, like:
>>> name = "eesmith"
>>> print("Who? {name}".format(name=name))
Who? eesmith
>>> print(f"Who? {name}".format(name=name))
Who? eesmith
but cause subtle errors because of the double string formatting: >>> name = "{x}"
>>> print("Who? {name}".format(name=name))
Who? {x}
>>> print(f"Who? {name}".format(name=name))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'x'
I'm glad I don't have to make this decision.I don't even like f-strings all that much. Sure, f'a = {a}' is nice and clean, but
f'sin(a) = {math.sin(a)}; cos(a) = {math.cos(a)}'
is IMHO worse than 'sin(a) = {}; cos(a) = {}'.format(
math.sin(a),
math.cos(a),
)
and it only gets worse for longer strings and/or more complex expressions. Python already had 3 ways of formatting strings (%, .format(), string.Template (which nobody uses)). Adding a 4th that IMHO is only a very small improvement over .format() and that only in a limited number of use cases, was not really worth the effort. What happened to "There should be one-- and preferably only one --obvious way to do it"?But making f-strings the default is 1000 times worse. Trading one set of errors for another one, making the language unnecessarily more complex in the process. Blurring the line between a string and formatting a string. What happened to "Explicit is better than implicit"? Bah.
The way I see it, currently:
* The separation makes them readable and easy to understand.
* Making them implicit will cause hell for many people who rely on user input (and I'm certain a lot would try to exploit that).
* The fact that they are readable, makes them easier to debug, as opposed to trying to figure out where did the "{hey ma look at what i can do}" SyntaxError came and who did what exactly.
like the following:
username = some_request_variable_1
password = some_request_variable_2
sql = 'INSERT INTO users (username, password) VALUES ({username}, {password})'.format(
escape(username),
hash(password, salt, per_user_salt)
)'
Good code? No. Exists in the real world? Almost certainly. Safe in Python currently? Assuming escape is implemented correctly. Safe in f-strings by default world? No.This also seems way less pressing than "most Python programs silently handle unicode wrong" as a reason to change the language.
Do we really need all four types? In particular, I expect use of the last type to be very rare.
Isn't it common in other languages to only have the second and third types? That is, they allow you to choose between using both escape sequences and variable interpolation, or using neither - there's no way to get one without the other?
>>> a = 42
>>> b = 'bar'
>>> 'foo %03d %r' % (a, b)
"foo 042 'bar'"
>>> 'foo {:03d} {!r}'.format(a, b)
"foo 042 'bar'"
>>> f"foo {a:03} {b!r}"
"foo 042 'bar'"
>>> __import__('string').Template('foo $a $b').substitute(locals())
'foo 42 bar'The reasoning behind this is because some people occasionally forget to include the `f` prefix? Then there's this:
>Smith would add a new "p" string prefix for plain strings, which would behave like ordinary strings today.
So what happens when reports start rolling in when some people occasionally forget to include the `p` prefix?
This is not quite true. PHP treats strings differently based on the quote character used - ' delineates plain strings and " delineates format strings.
Then, at 24 hours old, it has suddenly dropped to page 6?
When you write print(f"The value is {x}"), it cannot be translated.
Perhaps they could add a new prefix, like t"The value is {x}", and then gather all such strings for translation?
You are correct - translatable strings require late-binding, including possible re-ordering. As the Django documentation points out: 'an English translation may be "Today is November 26.", while a Spanish translation may be "Hoy es 26 de noviembre." – with the month and the day placeholders swapped.'
It adds that f-strings aren't currently supported... And I don't see how they could be supported.
https://mail.python.org/mailman3/lists/python-ideas.python.o...
As for stdlib, if I'm not mistaken, those packages will be published as standalone packages and simple `pip install` will be a migration path.
However, while I’m undecided on “all strings should be f-strings” I do know that “no more breaking changes” is not realistic and is a good way to ensure either a dead language or one with a hell of a lot of baggage
When Python 3.0 came out, u"" prefix was abolished and every u-string had to be changed. That change was found later to be a mistake and was reverted (I'm not sure what python version reverted it, somewhere around 3.3 I think). This proposal reminds me of that: change that seemingly sound good at first, but is simply not worth it.
Yes, there will be breaking changes and I'm not against them. I'm just against this one.