13 ms·
New string formatting in Python
- sauere 11y agoNot a fan. We already have 2 ways of formating strings in Python, we really should not bring in a third one. It may be true that "{} {}".format(a, b) is a bit verbose, but it is crystal clear and clean. Just remember the Python Zen: "There should be one-- and preferably only one --obvious way to do it." _and_ "Explicit is better than implicit."
- mixmastamyk 11y agoIt is the same thing as .format without all the noise.
- Grue3 11y agoNo, it's the same thing as .format, except limited to literals, so basically useless (hardcoding literal strings is bad for i10n).
- mixmastamyk 11y agoUseless... have you never used a shell? It's quite handy.
- Grue3 11y agoIf they're adding features purely for the convenience of python shell users, how about, I don't know, remove the need for significant whitespace (by adding "end block" statement). Because Python shell is a major pain to use when you try to copy-paste some code into it and it doesn't like the indentation levels. On the other hand I can copy-paste whatever into my Lisp REPL and it will run just fine. Or allow several statements per lambda. Saving a few keystrokes writing ".format" doesn't even register on the same scale of annoyance.
- mixmastamyk 11y agoI've been using Python heavily since about 2000. Approximately 2.5 times since then has whitespace been a problem, and which I fixed in under 10 seconds each time. Yet, the readability gains from removal of block delimiters in that time frame is uncountable. > Saving a few keystrokes writing ".format" doesn't even register on the same scale of annoyance It isn't just .format, it is: .format(long_variable_name1=long_variable_name1, long_variable_name2=long_variable_name2) This is a huge win that should have happened long ago.
- Grue3 11y agoBut you don't need to use long variable names in Python shell! Even one-letter vars are perfectly acceptable.
- mixmastamyk 11y agoWhen I wrote "shell" I was thinking of interpolation of bash, etc.
- scrollaway 11y agoString interpolation is one of those features where I'm really confused about the direction the Python team wants to take. It's implicit and magic, and yet another non-obvious way to do do string formatting. What's more, it's being hailed at a plus for localization which it isn't. Localizers should never, ever deal with string interpolation - anything past what .format() does is essentially untranslatable.
- eru 11y agoSomeone made a good argument that in order to support lots of languages, you actually need general functions not just strings to be put into .format() or interpolation. That's because some languages have complicated changes in the text depending on eg the number of things: not just singular/plural, but more complicated. Russian is one example.
- cbsmith 11y agoThat's a little misleading. In practice, what you need is a notion of a "context" for your formatting (often something that is aware of both the current i18n and l10n factors), and that context needs access to the fundamental objects that would be rendered in to a string. Effectively, the "format string" becomes an identifier for the particular message you want to render, though often the objects themselves are definitive enough. In that paradigm, interpolation/formatting/whatever might be the default mechanism employed by the context, but you don't want to have that as your explicit mechanism. You want one more level of indirection before you get to it. Some platforms make the mistake of having that context be tied to the thread, out worse still, a global, and that falls apart once you have any multiplexing logic (and the way python currently works with posix locales fully captures how terribly you can do this). Either way, I'd argue out really is a different problem from interpolation, and if you are trying to solve it using interpolation, you don't understand the problem.
- tenfingers 11y agoCan you clarify the last point? I do not get it. Can you make an example of where an extra indirect mechanism (besides interpolation) is _required_ for translation? I generally localize for western languages and write in many programming languages. The combination of gettext + python format strings has been working really great for me, and generally much better than other systems I've seen and put to use. In fact, the simplicity of gettext provides a very fast turn-around, and with translators experienced with the tool I never had problems. Python format strings also work great in this context, as I can supply an arbitrary dictionary of elements that the translator might need. The only real problem has been plural forms in complex text strings, where ngettext is not always sufficient. What method (name a project I can inspect) do you recommend as a good localization architecture?
- Walkman 11y agoI have mixed feeling about this. This will be the FOURTH way of formatting strings in Python. The other formattings will never go away.
- orionblastar 11y agoI think they keep the other formatting for backward compatibility in legacy code.
- bhaak 11y agoWhat's the fourth way? The article only mentions three.
- nothrabannosir 11y agoNot the op but Im guessing just using + (which calls .__str__(), iirc?)
- richardwhiuk 11y ago+ doesn't call __str__ internally. e.g the following is an error. a = 4 "a: " + a You have to do: "a: " + str(a)
- barely_stubbell 11y agoI agree that + is likely the 4th way. A minor correction to your comment: "+" calls the __add__ method (big surprise) - just fyi
- rdtsc 11y ago4th way is with templates: >>> from string import Template >>> s = Template('$who likes $what') >>> s.substitute(who='tim', what='kung pao') This will probably be TIL for many people. It is a surprisingly hidden feature. I for one, still like the "%s" % x instead of "{0}".format(x). It is simply shorter and I already know or use printf for C in other parts of the project. But with the new f"..." interpolation, I can see liking that more. I am all for being as concise as possible while still being explicit (if that makes any sense at all ;-) ).
- syrusakbary 11y agoQuite useful! If you want to have string interpolation in Python 2.6+ just use https://github.com/syrusakbary/interpy https://github.com/syrusakbary/interpy
- kseistrup 11y ago“They” could put string interpolation in the __future__ module: from __future__ import string_interpolation :)
- evrial 11y agoJust because simply one way isn't enough.
- richard_todd 11y agoThe motivation for PEP-0498 given in the article was the difference in verbosity between these two lines: "{} {}".format(a, b) "%s %s" % (a, b,) That's not very convincing. I was hoping this article would make a good case for interpolated strings, since it's starting to feel like Python is having an identity crisis. Type annotations especially took me by surprise, but string interpolation is another good example of an addition that doesn't feel like Python (imho, anyway).
- jdnier 11y agoThe more common case for me is to name the parameters. Especially with longer variable names, this gets tedious fast. Given >>> very_long_var_name_1 = 'spam' >>> very_long_var_name_2 = 'ham' compare >>> # Explicit but tedious and doesn't help readability: >>> print('{very_long_var_name_1}: {very_long_var_name_2}'.format( ... very_long_var_name_1=very_long_var_name_1, ... very_long_var_name_2=very_long_var_name_2)) spam: ham with >>> # Explicit but somehow feels dirty: >>> print('{very_long_var_name_1}: {very_long_var_name_2}'.format( ... **locals())) spam: ham and >>> # Still fits on one line. I think f prefix makes intent clear. >>> print(f'{very_long_var_name_1}: {very_long_var_name_2}') spam: ham
- toyg 11y agoThing is, * * locals() "feels dirty" but does exactly the same thing as f''. Except f'' does it implicitly, hiding dirt under the carpet. One day, that dirt will turn something into a bug; which is exactly why the Zen says "explicit is better than implicit". The best way imho would be: vars = {'short1': very_long_var_name1, 'short2': very_long_var_name2} print('{short1} {short2}'.format(**vars)) Easy and extremely unlikely to ever include the wrong variable.
- spicyj 11y agoExcept a linter or static analyzer can easily be taught to understand f"", but it's essentially impossible to reason statically about locals().
- monkmartinez 11y agoI'll just leave this here: https://www.python.org/dev/peps/pep-0020/ https://www.python.org/dev/peps/pep-0020/ "There should be one-- and preferably only one --obvious way to do it." There are a lot of warts on that snake, but I still really like using Python.
- aexaey 11y agoPEP20 sound amazing, but then when this only way end up being way too verbose/ugly, you are kind of stuck with it. Compare: #python import re m = re.search('(a.+)(d.+)', 'abcdef') if m: print(f"{m.group(1)},{m.group(2)}") #perl if('abcdef' =~ /(a.+)(d.+)/){ print "$1,$2"; }
- JoshTriplett 11y agoI don't know why Python re match objects don't support indexing; a __getitem__ method would allow m[1] and m[2] instead (or m['name'] for named groups). That aside, though, I don't consider brevity alone the most critical criteria for a programming language; that way lies APL. Expressiveness, yes, but not at the expense of clarity.
- eugenekolo2 11y agoPreferably one. Unfortunately they put in `format`, and can't remove it now. I think moving towards f-strings is a lot better and should be embraced.
- mixmastamyk 11y agoFormat is still needed for non-literals and user objects, this is just an extension of it.
- orf 11y agoThere are a couple of warts for sure, but Python is remarkably wart free. Compare it to something wart ridden like PHP or JavaScript.
- 11y ago
- rshaban 11y agoThere should be one-- and preferably only one --obvious way to do it. Hoping for a decision from the core team – having both f"" and .format is a pretty clear deviation from this principle.
- noobermin 11y agoWell, having both % and .format was already a clear deviation from it.
- deleted 11y ago[deleted]
- btmiller 11y agoThough I think the communication has been pretty clear that developers should stop using % formatting in favor of .format when moving to Python 3. Not so much a deviation, just a migration. Now that there's another alternative, there definitely needs to be some clear communication about what's going to be idiomatic going forward.
- deleted 11y ago[deleted]
- warbiscuit 11y agoExcept that they went and made .format() useless for bytes... which made everyone have to hang on to % for both 2/3 compatibility cases, and for all the cases where bytes templates were actually needed (all kinda of lowlevel wire protocols and file storage formats).
- Rangi42 11y agoAlso not a fan. The two existing methods of string formatting are sufficient: "%s %s %s" % (a, b, a) "{} {} {}".format(a, b, a) If you want placeholders to match variable names, you can do: "{a} {b} {a}".format(a=a, b=b) "{a} {b} {a}".format(**locals()) So this is just unnecessary (especially since the "f" prefix is easier to miss than a "format" method): f"{a} {b} {a}" And this is downright obfuscated—putting operators inside of string literals: f"{a + ' ' + b + ' ' + a}"
- deleted 11y ago[deleted]
- roywiggins 11y agoThe PEP says that locals() and globals() solutions were considered, and discarded: https://www.python.org/dev/peps/pep-0498/#no-use-of-globals-or-locals https://www.python.org/dev/peps/pep-0498/#no-use-of-globals-... You could argue that's not a good enough reason, but it's there.
- eugenekolo2 11y agoI certainly agree about your last statement, I have no clue what that would do without reading the spec. I'd guess an error, but apparently not.
- soheil 11y agoAm I crazy or PHP had this feature since forever? String templates can significantly improve programming speed specially for those of us who are keyboard impaired. Not having to remember how many %s' you need or if one of them should be %d and so on may to most seem just knit picking but personally it makes a day and night difference.
- deleted 11y ago[deleted]
- MereInterest 11y agoPHP has had it forever. Given PHP's reputation, I'm not sure if that is a good argument for this feature. Rather than '%s' and '%d', why not just use '{}' and '.format'? That way, each argument is converted to a string appropriately. If it becomes confusing with many arguments, it is easy to name the parameters '{myparam}'
- mixmastamyk 11y agoFrom another post: "{a} {b} {a}".format(a=a, b=b) "{a} {b} {a}".format(**locals()) Compared to this: f"{a} {b} {a}" Sorry that's about 1000% better. This should have been the one way to do it, originally. It isn't magic either, rather a simple compile-time transformation to existing format syntax. There's nothing new to remember besides a large reduction in noise.
- meowface 11y agoSome people deride string interpolation as not explicit enough, but I think it's extremely readable and adds clarity. Plus, with the `f` prefix, it's plenty explicit IMO.
- MereInterest 11y agoString interpolation is only being added for string literals, not for generic strings. This means that you still wouldn't be able to read a template from a file, then format text in. with open('template.txt') as f: template = f.read() formatted = template.format(**values)
- mixmastamyk 11y agoThat's a good thing due to security reasons as arbitrary expressions are allowed. There are plenty of templating solutions available.
- MereInterest 11y agoI agree. I was pointing out that the f'{a} {b}' syntax can't accomplish everything. Since it isn't intended as a complete replacement, the way `.format` is intended as a complete replacement for `%`, it will just add another string formatting technique without ever deprecating the old way.
- Animats 11y agoArbitrary string interpolation was proposed, in a way sure to result in security problems: "PEP 498 proposes new syntactic support for string interpolation that is transparent to the compiler, allow name references from the interpolation operation full access to containing namespaces (as with any other expression), rather than being limited to explicit name references. These are referred to in the PEP as "f-strings" (a mnemonic for "formatted strings")." "Full access to containing namespaces?" From strings? Bad, bad idea. This is currently marked as "deferred", but should be marked "rejected with extreme prejudice".
- such_a_casual 11y agoI never understood why I had to write (count=count, apples=apples, name=name) when a logical default would suffice.
- Walkman 11y agoI suppose you mean to take the variable names of the arguments without using keyword arguments? That's not possible because .format() is just a simple method call on str/unicode objects.
- such_a_casual 11y ago>That's not possible That statement is against my religious beliefs. Apparently we can stick an f in front of the string, but we can't have default values that work with locals()?
- mixmastamyk 11y agoThat would mean the formattee would have to dig thru its surrounding namespace. This solution is more elegant, the string is transformed into the equivalent format call at compile time, making the implementation tiny.
- such_a_casual 11y agoElegant for who? Adding a new syntax that doesn't exist in any language. vs. Using sensible default parameters. ----------------- An argument for why my suggestion would be bad: https://www.python.org/dev/peps/pep-0498/#no-use-of-globals-or-locals https://www.python.org/dev/peps/pep-0498/#no-use-of-globals-...
- mixmastamyk 11y ago> Adding a new syntax that doesn't exist in any language. Not true, look into the new interpolation features in C#, Scala, JS, Swift, nim, etc.
- jdnier 11y ago+1 for https://pyformat.info/ https://pyformat.info/ (mentioned in article), with some nice practical examples of equivalent %s and .format() formatting.
- hisham_hm 11y ago> That actually looks pretty nice but as Python 3.6 is slated for release in another 12 months you will have to wait a little longer. ...Or just do it in 28 lines of Lua: http://hisham.hm/2016/01/04/string-interpolation-in-lua/ http://hisham.hm/2016/01/04/string-interpolation-in-lua/ This is a nice showcase of how Lua's metamechanisms can be applied to do things that often require new features in other languages.
- kedean 11y agoI'd argue that it's not a good thing that you can just disregard block scoping willy-nilly from within unprivileged code.
- hisham_hm 11y agoIf you are in a context where you are concerned about "privileged vs. unprivileged" code, you have to sandbox way more than that, and Lua provides you many mechanisms to control that (more than any other mainstream scripting language). Disabling the "debug" library which I used there for traversing block scopes is the very first thing one does when sandboxing in Lua.
- c3534l 11y agoAt the very least, it sure looks a hell of a lot better. And using symbols and single-character abbreviations for types (in a dynamically typed language, mind you) and an overloaded % which has the extra syntactical rule that it only takes a single argument and so multiple replacements have to be done by throwing them all into a tuple is FAR more intuitive and readable than the way most languages do string formatting. Plus the alternatives, that require you bounce back and forth between the string and the variable it is replacing rather than read left to right the way humans are meant to read strings of text is a terrible design. Something as simple as string formatting should not rely on arcane and nuanced rules which are more or less arbitrary. You've all been programming in C-like languages for far too long to realize what a horrible design string formatting is. You can argue over "explicitness" all you want, the new way is easier to learn, easier to read, makes more intuitive sense, requires learning fewer rules, ad is close enough to the format string method that they work well together.
- sandGorgon 11y agoThe rift between Python 3 and Python 2 seems to be a fallout of the one-true-way philosophy. In fact, it almost stands the reason that Python 3.6 ought to be Python 4 if one-true-way needs to be upheld. If Python 3.6 is going to introduce multiple ways to do the same thing, there is no good reason to not merge Python 2 and 3 together and have both set of behavior co-exist with each other (__future__ or __past__). In one shot, you break the Berlin wall of Python.
- sametmax 11y agoApprently you haven't being using Python 3 much. It reduces the numbers of ways to do stuff a lot. - class stuff(object) vs class stuff; - range vs xrange; - itertools.izip vs zip; - itertools.imap vs map; - itertools.ifilter vs filter; - dict.items vs dict.iteritems vs dict.viewitems; - dict.items vs dict.itervalues vs dict.viewvalues; - dict.items vs dict.iterkeys vs dict.viewkeys; - __cmp__ vs __eq__ + __gt__; - sorted(cmp) vs sorted(key); They didn't fallout from the philosophy. They have been pragmatic and tried to balance the language design : gaining modern features vs making a robust base vs pleasing the legacy crowd. Is. Is. Very. Hard. And yes, we would all prefer to have less way to format. Would it mean I would prefer NOT to have fstring ? Certainly not, it's a great feature. We can't live in the past because it will make us not stand perfectly to the ideal we have. Real life is not ideal. But merging Python 2 and 3 ? With the string model completly reworked, that would be apocaliptic. Most people don't realize how deep the unicode change has been. I have been dev and teaching Python 2 and 3 for years. The amount of problems linked to UnicodeDecodeError dropped by 90% after the switch. Not because Python 2 model didn't work. Because nobody understand text. Most dev don't understand what text is. They just want to format string. That's what Python 3 helps to do, and it does it well. Mixing both would be like mixing olive oil and vanilla ice. Great on their own way, but use them together all you'll get a terrible meal.
- sandGorgon 11y agoat no point am I arguing whether python 3 is better or worse than python 2. That is an uninteresting conversation because the fact remains that less than 30% of all software is in python 3. Even when Google released Tensorflow, it was in Python 2 (and they employ core developers of Python). Do you seriously think anybody is thinking of dropping python 2 support by 2020 ? that will only create a fork. None of the core frameworks have upgraded in a decade. Look at Flask for example. So yes, I havent been using Python 3 much - there has been no reason to. the point I'm trying to make is how to get everyone on the same page. The reason Python 3 was api incompatible was because of the core tenet of one-true-way. All the functions you mentioned may be superior, but unless you give people a way to mix and match both in the same source , you will not have adoption. Or do you think Python 3 adoption has been successful ?
- bootload 11y ago"PEP-0498 tries to improve this situation by offering something that has been common to other languages like Ruby, Scala and Perl for quite some time: Interpolated strings." P3 '.format 'is fine, the only problem I have is forgetting the last ')' and vim picks this up. Is interpolation that good to introduce another way of doing things?
- losvedir 11y agoAs an outsider to the python community and full time ruby dev, this "controversy" baffles me every time it comes up. Lightweight string interpolation is obviously better! I think you all have string Stockholm Syndrome or something. The one counter argument that makes sense to me is that in general we shouldn't be doing easy string interpolation, since that way lies SQL injection, XSS, etc, and should instead rely on a stronger type system with binary text blobs, HtmlStrings, SqlStrings, etc, with automatic escaping into and out of the data type. But then that's not the case with Python now. If you're only trying to stick this string inside that string in a quick and dirty manner, I totally don't understand the reticence folks have to something the way ruby does it: "Name: #{first_name}".
- scrollaway 11y agoIf it's obviously better, would you care to share some better arguments than "people who disagree have stockholm syndrome"? Don't get me wrong, I'd like Python to have better, more obvious, more concise string formatting. However the last time we had this discussion, it was about str.format() and how it was going to be awesome and don't worry modulo-formatting will go away. Turns out it did not; modulo formatting is still there because why would it be removed. This is history repeating itself - are you actually baffled that some people learn from past mistakes?
- mixmastamyk 11y agoAll you have to do is try it once or twice to enjoy the readability and lack of positional mismatch bugs. None of the other techniques are going away. This time yes, no one is naive enough to think so.
- scrollaway 11y ago"Try it!" is not an objective argument (I have tried it extensively eg. in Bash and I neither like or hate it), and positional mismatch is not a concern when you use name-based syntax, which interpolation forces you into due to its nature.
- pvdebbe 11y agoI for one welcome the shorthand interpolation. String formatting is the thing we all do all day long (slightly exaggerated pretty much). Now if python would begin to support immutable values by default then I'd be most content, and Python complete enough.
- blubb-fish 11y ago> by offering something that has been common to other languages like Ruby, Scala and Perl for quite some time So funny ... the most prominent language known for this stuff is PHP ... and missing :D