6 ms·
Should all strings become f-strings?
- eesmith 7y agoI know I'm one who keeps having to go back to add the 'f' prefix to my strings. 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.
- Traster 7y agoI know this is just a personal feeling, but I prefer paying the cost of writing f every time to have an indicator of where I'm expecting substitutions, rather than having the default behaviour of the language be that they're going to interfere with your string literals. It just feels like doing something non-obvious by default is more likely to cause issues, whereas the person forgetting the f in an f-string clearly knows about f-strings and so is going to find their error much more easily. Having said that, I'm not a someone who writes particularly pythonesque code in the first place so my sensibilities don't carry a huge amount of weight.
- ChrisSD 7y agoTalking of probably unpopular opinions: I'd prefer that all strings be raw by default so escape characters aren't processed at all. Characters like `\n` or `\uXXXX` can be useful sometimes but I'd prefer to opt in to that. In fact, with f-strings its easy to simple use a constant instead of `\` escape sequences. Admittedly this would be too big of a change to make now.
- mantap 7y agoI think the way it works now is correct. Using escape characters is more common than writing strings with backslashes. The more common case should be default.
- abstractbeliefs 7y agoI feel similarly. I'm unsure where such a drive is coming from. I know it's just a philosophy, but the whole "explicit is better than implicit" thing stands to test here, and it looks like Python could deviate from it yet again. 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.
- eternauta3k 7y agoSorry, no more breaking changes after 2->3.
- smcl 7y agoBreaking changes will inevitably be necessary in any language. Take the recent-ish discussions about cleaning out the deadweight from the Python stdlib, there's a bunch of modules that are basically unused by users, untouched by maintainers and are therefore effectively deprecated. Taking a "no more breaking changes" philosophy means continuing to semi-support these into eternity, when realistically many can be cast off with a reasonable notice period and a well-documented migration path.
- selectnull 7y agoI think we should not think in absolutes! There are breaking changes that are small and acceptable, and there are those that will require unnecessary changes to source code to port them to new version. I don't think python community has yet recovered from 2to3; and I'm not saying it shouldn't have been done; I'm saying I wouldn't like a repeat in 3to4. 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.
- smcl 7y agoWe are in complete agreement. 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
- selectnull 7y agoPersonally, I'm against "all strings should be f-strings" just because it would cause changes to source code that I don't find necessary. 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.
- 01walid 7y agoNo. Explicit is better than implicit.
- axegon_ 7y agoThis. I honestly love the f-string syntax but the fact that there is a clear separation is what makes them appealing - I find it far more convenient to have f"{v1}, {v2}, ... {vN}" vs "{v1}, {v2}, ... {vN}".format(v1, v2, ... vN), not to mention % v1, v2, ... vN. 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.
- globular-toast 7y agoIt is explicit. You have to use braces to get the variable expansion.
- muglug 7y ago> Larry Hastings pointed out that PHP strings are format strings by default and "the script kids love it." This is not quite true. PHP treats strings differently based on the quote character used - ' delineates plain strings and " delineates format strings.
- cpach 7y agoDoes anyone know if this is actively discussed at the moment? If so, on what mailing list?
- tda 7y agoGuido discussed the latest language summit on this podcast: https://pythonbytes.fm/episodes/show/179/guido-van-rossum-drops-in-on-python-bytes https://pythonbytes.fm/episodes/show/179/guido-van-rossum-dr.... I believe he mentioned default f-strings were discussed and rejected.
- pansa2 7y agoThe appropriate place would probably be the python-ideas mailing list: https://mail.python.org/mailman3/lists/python-ideas.python.org/ https://mail.python.org/mailman3/lists/python-ideas.python.o...
- jorams 7y ago> Larry Hastings pointed out that PHP strings are format strings by default and "the script kids love it." 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.
- zem 7y agoruby does this too, and I think it's a great design. I know it's too late for python to go that route, but I wish they had way back when, rather than having single and double quotes be the same thing.
- BerislavLopac 7y agoPython's mechanism for this is using a single-character prefix, which would still be needed even if it followed the Ruby/PHP syntax -- simply because Python has at least four different types of string literals: * 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 bytes
- pansa2 7y agoThere are also `fr`-prefixed strings, which do substitution but no escaping, and `br`-prefixed raw byte sequences.
- BerislavLopac 7y agoExcellent point, thank you! There 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"...
- jpxw 7y agoI think the current explicit f-string syntax actually aids readability. When I see an f-string, I’m immediately aware that some interpolation is taking place, and my eyes can quickly scan for the braces. Additionally, it helps me to differentiate between “static content” and “dynamic content”, for want of a better phrase.
- mcherm 7y agoIf I were creating a new language today there is absolutely no question in my mind: I would have the default string type support interpolation. It means that there is a particular character or character combination ("{" for python, "${" for JavaScript, etc) which is not allowed in strings without escaping -- that isn't much of a usability problem: we live with the need to escape new lines in strings and no one even thinks twice. 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.
- dragonwriter 7y agoNo, all strings shouldn't be f-strings, because if they were you'd either need to resort to weird, awkward escaping or invent a new prefix to have template strings that you interpolate repeatedly later, and in either case break backward compatibility. Both template strings and immediately interpolated strings are needed, and the current “normal string” vs. f-string divide allows expressing both easily and clearly, and there is no improvement to that status quo in this area that is worth the cost in backward compatibility.
- pydry 7y agoThe awkwardness of escaping makes me wonder what some vehemently pro f string people are smoking. .format is a neat, clear, terse way of constructing strings like so: 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.
- bocklund 7y agoYou can actually put those expressions in your format() into the f-string braces, no escaping required.
- Mister_Snuggles 7y agoYour first example works fine as an f-string without resorting to escaping, 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.
- steerablesafe 7y agoNo
- Nicksil 7y agoNo. Please no. There's no need for this. 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?
- hawski 7y agoIf f-strings would become default, I would hope for from __past__ import...
- globular-toast 7y agof-strings should have been the default right from the start, with a prefix (like r"") to turn it off. In that way it would be similar to bash. But I think that ship has sailed. Like any mature language Python will have to live with some of the unfortunate decisions of the past. Thankfully Python is still far better than most languages in that regard.
- fhennig 7y agoSo just because sometimes you forget to put a single character in front of your strings, you'd like to make a breaking change in the language that affects one of the must fundamental data structures in the language? I don't think thats a good idea.
- searchableguy 7y agoI wonder if they can use a linter to catch it.
- leetrout 7y agoGo linters catch it so I would bet yes they could but there might be a few false positives.
- pansa2 7y agoI recently discovered that Python supports four different kinds of string literal (plus two kinds of `bytes` literal). Strings can have no prefix, or be prefixed with `f`, `r` or `fr`. This proposal simply changes the prefixes to `p`, none, `pr` and `r` respectively. 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?
- j0057 7y agoAnd don't forget we can do string formatting four ways now! >>> 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'
- roelschroeven 7y agoPlease for the love of f"{deity}" don't do this. Making the language more complex, introducing p-string, just because people sometimes forget the f prefix? And they're not going to forget the p prefix? 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.
- benibela 7y agoMore important than f-strings are translatable strings. 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?
- eesmith 6y agoSee the gettext module, at https://docs.python.org/3/library/gettext.html https://docs.python.org/3/library/gettext.html , where gettext() is usually aliased to "_()" so people can write _("int'l string") . There are also tools to extract such strings. 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.
- Macha 7y agoI feel like this proposal didn't learn its lesson from the need to port u'' string prefixes to Python 3.2. How would one write a string that should not need interpolation in current Python versions so it doesn't silently get interpolated in Python 3.defaultfstrings? I also worry about codebases that don't get updated, seem to work, but silently open up attacks: 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.
- pansa2 7y agoCan anyone explain what happened to this submission? There was no interest when it was first posted, then at 20 hours old its submission time was reset and it was suddenly on the front page. Then, at 24 hours old, it has suddenly dropped to page 6?
- eesmith 6y agoI believe that's moderator intervention. When they think a topic is overlooked and deserving, they reset the timer to give it another change.
- Grue3 7y agoI don't think we have a single f-string in the entire Python 3.7 codebase in the project I'm working on. They seem rather useless to me. I often pass a string like 'this is a template with {var}' into another function that uses .format(var=something) to fill out the template. This seems impossible with f-strings. On the other hand everything that f-string can do can be just as easily done with .format, except in a more explicit and Pythonic way.