10 ms·
I absolutely LOVE format strings. Whereas before, you had to format strings in one of these ways (among other more verbose ways): "My name is {} and I am {}
by chrisshroba 10y ago
I absolutely LOVE format strings. Whereas before, you had to format strings in one of these ways (among other more verbose ways):
"My name is {} and I am {} years old".format(name, age)
"My name is %s and I am %s years old" % (name, age)
"My name is {name} and I am {age} years old".format(name=name, age=age)
Now, we can finally use f-strings, where anything in brackets is eval'ed, with the result subbed in:
f"My name is {name} and I am {age} years old."
- sakubara 10y agoI can imagine this to be especially useful in implementing __repr__ and __str__ for classes.
- kbutler 10y agoBut I really miss "There should be one-- and preferably only one --obvious way to do it." (Conflict between improvement and backward compatibility, but I miss it.)
- bbatha 10y agoThe quote in context shows no conflict: In the face of ambiguity, refuse the temptation to guess. There should be one-- and preferably only one --obvious way to do it. Although that way may not be obvious at first unless you're Dutch. It pretty clear that if you support python 3.6 you should use `f` strings.
- kbutler 10y ago> It pretty clear that if you support python 3.6 you should use `f` strings. And if you support any earlier version of python, you cannot use f strings. Hence, there is a conflict between improvement and backward compatibility.
- ghshephard 10y agoBut for new projects, where you can chose the version of Python you want, there is no requirement for "backwards compatibility" - it's not as though Python 3.6 isn't available for every platform that 3.5 was on.
- amyjess 10y agoYeah, this is the biggest reason why I'm excited about 3.6. I'm still using % for all formatting because .format() is so ugly and verbose, but I'll switch to f-strings when I actually get the opportunity to use 3.6. In fact, when the PEP first appeared I immediately decided that from now on, I'd write all greenfield projects in Python 3 just so I can take advantage of f-strings as soon as I can use 3.6 (yes, this of all things was what made me switch from 2 to 3). Though I think it would be cool if you could have a deferred format string, like so: template = 'My name is {name} and I am {age} years old. Next year I will be {age + 1}!' name = 'Amy' age = 32 formatted = template.apply() # formatted = 'My name is Amy and I am 32 years old. Next year I will be 33!' So that way you could store the template as a constant somewhere and apply it after receiving input from the source of your choice. You can kind of do that with [0], but it doesn't evaluate expressions (so the age + 1 thing won't work). [0] .format(**locals()) # putting it here because HN eats the asterisks if it's not indented
- bastawhiz 10y agoYou can always put your f-string in a lambda if you don't want to evaluate it immediately. Pulling values from the scope of the function you call your apply() method from, though, is some scary magic. I wouldn't be confident that I hadn't screwed that up.
- spraak 10y agoWhat about.. def template(name, age): return f"My name is {name} and I am {age} .." formatted = template('Amy', 32) ? [Edit: I only started learning Python recently, and this is how I'd think of doing it come from JS: const template = (name, age) => `My name is ${name} and I am ${age}`; const formatted = template('Amy', 32); ]
- mixmastamyk 10y agoCheck string.Template from the docs.
- mixmastamyk 10y agoCool. string.Template might be what you are looking for.
- wyldfire 10y agoI would frequently use "My name is {name} and I am {age} years old".format(**locals()) ... but I always felt a little guilty like this is some kind of dynamic-programming-on-steroids trick that I should use sparingly.
- perlgeek 10y agoAs a long-time Perl developer, it's kinda amusing that this is the new big Python feature now, when shells, awk, Perl, PHP and Ruby have had string interpolation for ages. Yes, I know you can do more with format strings than plain interpolation, but that's all that the basic examples show. (Also: Perl has allowed underscores in number literals for ages).
- tannhaeuser 10y agoawk doesn't have string interpolation, though. --- "Avoid programming languages starting with the letter P except Prolog"
- throwaway7645 10y agoDo you use Prolog in day-to-day work?
- tannhaeuser 10y agoCurrently, no. But I've implemented an (ISO-)Prolog engine (twice, even). Tragedy is, there are more Prolog engines than Prolog programs, just as there are more web frameworks than web apps ¯\_(ツ)_/¯
- rantanplan 10y agoString interpolation isn't a new feature, you are confused. Python just got one more way of doing string interpolation.
- TAForObvReasons 10y agoprintf-style specifiers and substitutions, like in the examples GP provided, aren't considered string interpolation.
- rantanplan 10y ago> "My name is {name} and I am {age} years old".format(name=name, age=age) This is a textbook example of string interpolation. You can look it up on wikipedia. I am not sure what you mean.
- spraak 10y agoDoes anyone else find Python just as 'crazy' as Javascript gets called?
- lmm 10y agoNo. Python is probably the least crazy mainstream language IMO. (Except the middle-endian for comprehensions, and the silly truthiness definition for dates)
- spraak 10y agoI find it weird that there are built-in functions like `map` but string objects still have methods like `split` - but I am so used to everything being a method on an object in JS. I mean that it feels so much nicer to do: let x = [ 1, 2, 3].map(i => i * 10) than x = list(map((lambda i: i * 10), [ 1, 2, 3 ]))
- lmm 10y agoThere's a lot of value in having the option of using top-level functions e.g. len. Sometimes something is more natural as a method, sometimes it's more natural as a function. In the specific case I probably agree with you, but I don't think any of the differences qualify as "crazy"; generators being lazy by default is a reasonable choice (though I think the wong one), map is often used partially applied so it's nice to have it available as a function, => was only recently added to javascript and I would hope Python will get something similar sooner or later (though I'd rather have scala-style _).
- spraak 10y agoAll good points, thanks for explaining!
- otakucode 10y agoWhat does the _ do in Scala? I've not used Scala, and it wasn't terribly clear from context unless you mean they use _ exactly as javascript uses => (which would seem really weird to me so I'm assuming its different, apologies if that is asinine).
- emidln 10y agoObligatory xkcd: https://xkcd.com/927/ https://xkcd.com/927/ In typical perl^Wpython spirit, we now can save a few characters by typing: f"My name is {name} and I am {age} years old." instead of: "My name is {name} and I am {age} years old.".format(**locals()) Look how much typing we saved! Now we just have to explain to new users that their strings get eval'd for stuff in brackets, but only when the string is prefixed by `f`...
- munchhausen 10y ago> "My name is {name} and I am {age} years old.".format(locals()) Well that's a definite code smell.
- emidln 10y agoDon't realize that this is exactly what f-strings are doing? If you accept the `f""` version but not the `"".format_map(locals())`, you're lying to yourself[1]. At least the `str.format_map(locals())` isn't magic (and IMO, much more pythonic (by virtue of explicit), although not as pythonic as `str.format(template_var=scoped_var)`). The only way `str.format_map(locals())` is a code-smell is if the people working on the code don't actually know Python. Builtin methods of core types, dictionary unpacking, and builtin functions are all extremely common and only complete novices at python would find any issue with them. Compare that to what you need to know when you encounter `f"hello {name}"`: 0) am I working with Python 3.6+? 1) when does replacement happen? 2) what scopes are examined for substitution? Of course, 2) is a trick question because you EVALUATE ARBITRARY PYTHON EXPRESSIONS IN THE FORMAT STRING![2] [1] Technically, PEP-0498 states that we're not exposing a full locals() or globals(), but this actually matters very little. The danger here is that both .format() and f"" use object.__format__() (falling back __repr__ IIRC) to figure out the replacement. If your object.__format__() is malicious, it gets access to more data than it needs. However, since python has zero security model, if it's malicious, it pings whatever command and control server it's reporting to and starts up a thread listening for commands anyway (aka you're fucked). Realistically, this means that, you might leak credentials (or other sensitive information) to third party loggers, but only if your method for censoring outgoing log/exception data is a a poorly-built blacklist. [2] https://www.python.org/dev/peps/pep-0498/#supporting-full-python-expressions https://www.python.org/dev/peps/pep-0498/#supporting-full-py...
- golergka 10y agoSo python now has 4 different ways to do this? Ugh.
- Sean1708 10y agoIt's a fair complaint but they tried deprecating % and that ... well ... ended badly.
- cookiecaper 10y agoYep, can't please everyone. Someone is going to complain that you broke backwards compatibility if you remove something, and someone is going to complain that you've muddied up the language if you don't. Python 3 was an attempt to straddle that chasm and it definitely caused problems. I think you just have to play it by ear. Old formatting styles seem like one of those things you want to leave alone for a really long time, because they're so common that it'd be a major PITA to fix all occurrences, and because it doesn't seem like there's an obvious negative ramification to allowing the old styles to continue to evaluate according to the old methods.
- mixmastamyk 10y agoIt is built right on top of .format(), so perhaps it's more accurate to say 3.1 ways.
- makecheck 10y agoI’m curious actually why an f-string syntax is considered OK when a print-statement is not. I mean, there’s a precedent for short built-in functions like len(), and apparently 'print "x"' as a statement was terrible so 'print("x")' replaced it. If they wanted such consistency, shouldn’t they have used 'f("{a} {b}")' or something? Or alternately, allow p-strings like 'p"hello, world"' to print?
- richard_todd 10y agoThat would not be a traditional function, because you want {a} to be evaluated in the context of the caller, rather than the context of f.
- sirtaj 10y agoAs I understand it, print() was created not from a sense of consistency, but because a few awkward cases could be simply solved by turning print from a statement into an expression. Use in lambdas would be one example.
- mixmastamyk 10y agoI don't like the extra parens, but I made an editor shortcut to alleviate that. Other cases such as redirecting to a file, and changing the line ending are handled much more intuitively with the print function.
- NegativeLatency 10y agoThe prefix isn't new, there were already u, b, and r strings.
- rtpg 10y agoIn order to implement `f` as a plain function with same behaviour as g-strings, you would probably have to do some stack trickery to properly capture locals. In fact, I don't think it would be possible to write such a function in the general case, because it's ambiguous what environment you would need to use. For example: def call(func, arg): a = 2 return func(arg) a = 1 print(call(f, "{a}")) Does this print 1 or 2?
- coredog64 10y agoWhen can I expect to import this into 2.7.x from future?
- rwmj 10y agoMy colleague found a little bug in his code when he upgraded to Python 3.6 last week. Python ≤ 3.5 allowed "\o" (evaluating it as a backslash followed by a letter o). Python 3.6 now (correctly) treats this as a warning.
- mixmastamyk 10y agoYeah! Believe it or not (shameless plug) it was yours-truly who finally got the idea to snowball through the gauntlet at python-ideas. The extent of my participation, but still, am happy with how it all turned out. (pat pat) Python is no longer inferior to Bash and Perl for short scripts and more concise. Looking across the modern language landscape, this functionality is becoming an industry standard. The format string is also a little more sophisticated that it looks on the surface. Still, I was a bit down that so many showed up to complain about it, mostly with purity or adversity-builds-character arguments. I'm glad lots of people are enjoying it.
- aeijdenberg 10y agoThe problem I've found is that when we start using cute tricks like the old "xxx" % locals(), or the newer f-strings, is that we tend to start forgetting basics like escaping the strings that we're substituting in. For the example above, this might be fine, but most examples that I see using this kind of thing are things like: "select * from foo where id = '%s'" or "<input type='hidden' name='foo' value='%s'/>" or "rm -rf /path/to/customer/%s" I tend to think that in general appending strings is more often than not quite a dangerous operation, and it behooves the caller to need to have a long think about exactly how the strings being substituted in need to be escaped - as it's pretty rare that they don't need to be.