7 ms·
Flynt: Convert old Python string formatting to f-strings
- sitkack 6y agoF strings are the f"ing shit"
- ganstyles 6y agoI like them for the most part. Almost always more readable to out things in the brackets rather than the .format at the end, and always better than the %. Occasionally I still use .format with really long strings though for readability.
- ignoranceprior 6y agoGP said that f-strings were "the f***ing shit", not "f***ing shit", so I assume it was meant as a positive comment.
- uranusjr 6y agoUnless the tool does something more than its tagline, pyupgrade[1] offers the same functionality and much more. [1]: https://github.com/asottile/pyupgrade https://github.com/asottile/pyupgrade
- ivan_ah 6y agopyupgrade seems to do lots of useful stuff; thx for link! I guess you need the `--py36-plus` CLI option to reproduce the desired behaviour https://github.com/asottile/pyupgrade#f-strings https://github.com/asottile/pyupgrade#f-strings thought that might result in lots of other edits to the source, this in particular seems unwarranted "foo".encode("utf-8") --> "foo".encode() because the default encoding in py3+ is utf-8. What happened to explicit is better than implicit?
- uranusjr 6y agoYeah, I’d say not all rules in pyupgrade are universally popular. Fortunately I seldom see it used as a CI checker or pre-commit hook, and much more often used as a one-off transition tool with output manually reviewed instead (more like 2to3 than black).
- digianarchist 6y agoDo f-strings play nice with PyLint these days?
- jojo14 6y agoI don't mean to be rude, but what is the point ? AFAIK the % operator is not deprecated. In fact % formatting being syntactically near identical to C is a feature to me. I use format strings as well depending on context. % formatting being older doesn't mean it's obsolete. That said it is cool to design a script to transform your code and any time you spent in the developing of automation is time earned.
- solveit 6y ago>what is the point ? I can see an in-house style guide strongly recommending f-strings over % formatting
- stigz 6y agoAlso can improve performance.
- solveit 6y agoSure, but how often is string formatting the bottleneck on performance?
- greatgib 6y agoDo you have a proof of that? I think that it might be the opposite.
- yunruse 6y agoIt’s not a proof, but it makes logical sense: f-strings can be noted and compiled at runtime, whereas regular strings must be compiled every time string.format notices them. Maybe middling on one run, but reasonably useful in a long loop
- BerislavLopac 6y agoF-strings are much faster: In [4]: a, b, c, d = ("123", "456", "789", "0ab") In [5]: %timeit a + "-" + b 139 ns ± 10 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each) In [6]: %timeit "%s-%s" % (a, b) 198 ns ± 13.8 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each) In [7]: %timeit "{}-{}".format(a, b) 248 ns ± 9.17 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) In [8]: %timeit f"{a}-{b}" 99 ns ± 2.48 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each) In [9]: %timeit a + "-" + b + "-" + c + "-" + d 344 ns ± 10.3 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) In [11]: %timeit "%s-%s-%s-%s" % (a, b, c, d) 290 ns ± 9.64 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) In [12]: %timeit ''.join([a, '-', b, '-', c, '-', d]) 245 ns ± 2.32 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) In [13]: %timeit "{0}-{1}-{2}-{3}".format(a, b, c, d) 471 ns ± 23.6 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) In [14]: %timeit f"{a}-{b}-{c}-{d}" 176 ns ± 11.9 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
- kelsolaar 6y agoAwesome! This was something I needed and wanted to write, thx for making it!
- deleted 6y ago[deleted]
- eesmith 6y ago> There is a case when this will behave different from the original - if var is a tuple of one element. Hmm. I have a long habit of (almost) always using a one-element tuple. Consider: "foo %s" % x The % operator on strings has a special case for tuples: >>> x = "bar" >>> "foo %s" % x 'foo bar' >>> x = ("bar",) >>> "foo %s" % x 'foo bar' If you really want str(x) and are unsure that x might be a tuple, then you must use the tuple form: >>> "foo %s" % (x,) "foo ('bar',)" or for a more involved example: >>> from collections import namedtuple >>> x=namedtuple("Foo", "foo")("bar") >>> "foo %s" % x 'foo bar' >>> "foo %s" % (x,) "foo Foo(foo='bar')" This might occur with input validation, like: if isinstance(x, int): return f_int(x) elif isinstance(x, float): return f_float(x) else: raise ValueError("Unsupported value: %s" % (x,)) In my code base there are at least 347 occurrences of this form: % cat *.py */*.py | egrep -c '% \([a-zA-Z0-9_]+,\)' 347
- spinningslate 6y agoSlight tangent, but kudos for the quality of the readme. Thorough, complete and to the point.
- greatgib 6y agoIt is only my personal opinion but I find the f-strings to be conceptually bad: It might be a little bit easier to writer, but now you have magic and also code that is mixed within what should be simple strings. It is so easy to have suprising bad side effects because some operation would have been hidden in strings.
- dijit 6y agoIt makes sense when you consider other string methods. r"" strings for raw representation (this breaks most syntax highlighters though) u"" for unicode string b"" for bytes string. f"" would totally fit as a "formatted string". (R&B strings were available in python2, for context).
- xorcist 6y agoThey are more like templates than strings, which makes things like internationalization unnecessarily hard. Personally I find the use case between simple %-interpolation of dumb strings and full blown templates pretty small.
- pydry 6y agoI agree but it's not a popular opinion. I liked the ability to put semi-complex anonymous expressions in format and reference them with {}. If you did this it was still be obvious what was going on without having to create variable names like comma_separated_list_of_emails. Technically this is possible in f strings but it leads to an escaping mess. You wouldn't want to put a comprehension with a ','.join in there, for example. Even when you did use variable names (e.g. "{addr_list}...".format(addr_list=...") you could safely use shorter names because the scope was tighter.
- whalesalad 6y agoSo easy? I’ve never created a side effect in my life with f-strings. The same could be said about virtually any feature of any language. Why would you want to impose artificial constraints on yourself? I really dislike the argument “people will hurt themselves, let’s go back to the old way“
- CrLf 6y agoHaving a choice on when to use the existing string formatting methods is a feature. I tend to use ‘%’ a lot for it’s compactness and f-strings most more rarely (admittedly there doesn’t seem to be much reason to use .format these days). In general I don’t understand the need to hard-standardize code. Making subtle decisions depending on context is an important part of programming, please let humans decide and don’t use these types of tools in commit hooks...
- afarrell 6y ago> Making subtle decisions depending on context is an important part of programming. Yes, and so is deciding what context matters across a whole team or team-of-teams.
- BerislavLopac 6y agoOne case where .format comes in handy: your_dict = { "some": "awesome", "from": "out of", "dictionary": "mapping", } "insert {some} values {from} a {dictionary}".format(**your_dict)
- OskarS 6y agoThat is a very neat trick indeed, I'll have to remember this one!
- CrLf 6y agoThis can also be achieved using '%': your_dict = { "some": "awesome", "from": "out of", "dictionary": "mapping", } "insert %(some)s values %(from)s a %(dictionary)s" % your_dict WRT .format, '%' is safer to use with untrusted (well, semi-trusted) format strings, whereas .format can lead to code injection (in more insidious ways than with f-strings).
- galbar 6y agoSome years ago I made a script to backport a project I had developed in py3.6 on my free time but when I wanted to use it in prod at work it had to be py3.4: https://github.com/Galbar/norfs/blob/adb2a4ea885997352a1e24da8a7f45f35932a844/backport-py3.4.py https://github.com/Galbar/norfs/blob/adb2a4ea885997352a1e24d... It was a fun experience :)
- BerislavLopac 6y agoBTW, this is a great resource that compares the ways to do different formatting actions in two different styles - the %-based one (what they call "old style") and the .format one ("new style"): https://pyformat.info/ https://pyformat.info/