7 ms·
Fstrings.wtf
- underdeserver 1y agoCute quiz! As a reminder, if you're doing anything even slightly complicated with f-strings (beyond :x or var=), leave a comment.
- zahlman 1y agoOhg abg orgjrra gur oenprf! ;)
- Disposal8433 1y agoAs someone who works on a codebase with almost no comments, please leave a comment for every block of code that does something and explain why (1 comment for every 5 or 10 lines of code should be fine). And for regex you have this in some languages: https://docs.python.org/3/library/re.html#re.X https://docs.python.org/3/library/re.html#re.X
- cluckindan 1y agoPlease include any technical and especially business reasons in the ”why”, please.
- elteto 1y agoHey, I’m doing complicated things with f-strings so I’m leaving a comment as requested.
- zahlman 1y ago21/26, with a couple of sleep-deprived brainfarts and a misclick. Learned very little, although I had the wrong reasoning for one of the ones I got right (tested afterward). I don't even use the {var=} thing or walrus operator, though. I would definitely not do nearly as well on jsdate.wtf. I really still think JS has the greater WTFs.
- the_mitsuhiko 1y agoI was not sure about the difficulty. Python has some really weird behaviors with some of the custom __format__. For instance f"{'None':<010}" will pad out, but f"{None:<010}" will error. The only one I ended up putting in is the gotcha that bool is an int subclass and gets the int behavior for custom format parameters (which almost sounds like a bug). f'{''''''''''''}' is also a weird one, but that is mostly an issue with the string concatenation syntax and not fstrings :) There definitely are some more odd / confusing ones.
- OJFord 1y ago> For instance f"{'None':<010}" will pad out, but f"{None:<010}" will error. Is that any different than being surprised that 1 + 1 is 2 and '1' + '1' is '11'?
- lionkor 1y agonot really, since None stringifies to "None", so you would expect None -> "None" -> padding and whatnot added
- the_mitsuhiko 1y agoI don't know, but I find this quite confusing: >>> f"{'42':<10}" '42 ' >>> f"{42:<10}" '42 ' >>> f"{None:<10}" Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unsupported format string passed to NoneType.__format__ (Or any other type. What can be padded is quite inconsistent)
- Retr0id 1y agoI made a mistake on 7, but wouldn't have done if I had syntax highlighting.
- deleted 1y ago[deleted]
- istrice 1y agoNice quiz! I admit I was surprised a couple of times (especially with f"{1<5:1<5}"), many of these features are hardly ever needed
- Liftyee 1y agoI like this quiz format much more than just reading a doc because I get to guess what it might do before finding out, which reinforces how well I remember it. As a Python amateur I had no idea fstrings were so powerful!
- frickit 1y agoThese games just reinforce that I’m an idiot.
- meinersbur 1y agoJust learned about the ellipsis statement and the !a modifier (I already knew !r and !s).
- tialaramex 1y agoString interpolation is one of those features like inference where if you've had it before then going without is very annoying, and so you add some and that's nicer, then you add more, each step seems like it's an improvement, and then one day you realise you're looking at unintelligible nonsense and you say "Oh no, what have we done?" This is unusual, often CS would love to have as much of whatever as we can, but mathematics says no that's literally or practically impossible - but here both none and lots are awful and shouldn't be permitted. One option, which Python and C# both picked is, well, leave it to taste. You can write sixteen pages of layered expressions in the uncommented interpolated string and it'll work, but your colleagues will curse your name and plot your destruction. Or at least you'll fail code review if you enforce such things. Another option, in standard C++ 23 today for example, is refuse to take even the first step. You can have rich formatting, but standard C++ does not provide interpolation at all, if you want to format six parameters then pass them as parameters. I'm happy with Rust's "Only a tiny bit of interpolation" where you can interpolate only identifiers, not any other expressions, but that's definitely more interpolation than some will be happy with, yet of course in some cases it's not quite enough.
- Waterluvian 1y agoPurity and practicality are at odds and every language finds a different balance between the two. There is no one correct balance so busy minds will inevitably have loud opinions they want accepted as the one correct balance.
- almostgotcaught 1y ago> busy minds cute pun but compared to busybodies it really hides the implication (i thought you were talking about people with adhd at first).
- sublinear 1y ago> CS would love to have as much of whatever as we can, but mathematics says no What does this have to do with either topic?
- cluckindan 1y agoIf this was JavaScript syntax, most of the comments would be lamenting the unintuitive syntax and weird features.
- crazygringo 1y agoRight, I assumed the real point the quiz was making is that Python is as full of footguns as JavaScript, since I've seen this type of thing for JS a bunch of times. Not saying I agree, but was definitely expecting that to be the main topic of discussion here...
- jvolkman 1y agoBut if it were Perl, they'd be celebrating.
- somat 1y agoOn the subject of javascript template literals. Do they really not support the equivalent to let template = 'hello ${name}'; let n1 = template.format({ 'name':'joe' }); let n2 = template.format({ 'name':'bob' }); I am not really a javascript programmer. but I was writing some and wanted to store a bunch of templates then fill them out dynamically and was unable to figure out how to do it with the native javascript template system. So I ended up having to write my own. As it appears to be a huge obvious hole in missing functionality, I have to ask. Am I holding it wrong? While writing this up I was rereading the mdn page on template literals, perhaps tagged templates would do what I wanted, I don't remember why I did not use them(I think it is still not possible to store the template), but on first glance, yeah, lamentations about the unintuitive syntax and weird features.
- cluckindan 1y agoTagged templates probably won’t help, or will be quite messy. But you can just use a thunk with some parameter destructuring: const tpl = ({ name }) => `hello ${name}`; const n1 = tpl({ name: "joe" }); const n2 = tpl({ name: "bob" }); Or if you don’t like the duplication of property names, you could do it without destructuring: const tpl = (o) => `hello ${o.name}`; Look for the free online book ”You don’t know JS”, it is good reading.
- WithinReason 1y agothanks I hate Python now
- kosolam 1y agoI doesn’t exist. Lol
- psychoslave 1y agoAwesome, makes me glad I didn't touch Python for years now. Hell is paved with good will I guess. Probably Justine should update https://justine.lol/lex/ https://justine.lol/lex/
- skrebbel 1y ago> makes me glad I didn't touch Python for years now. C'mon, every language has quirks.
- bogtog 1y agoMany of these are desirable features!
- sfink 1y ago...if you think Python is irregular, what the heck are you using for scripting instead??!
- psychoslave 1y agoRegularity, as the number of rules a system rely on, is not the only variable, and not even the effectively most significant one, when it comes to language ergonomic. Just like terseness, it's an easy to measure and easy to make low in ways that are actually working against ergonomy. If you look at Justine post, Ruby is given as the hardest to make highlighted correctly. Much of it I guess however pertains to the many ways it's possible to switch to in place string feeding. It's harder to deal with for automated parsers, but it's generally not pushing human writers to encode in a way that is later harder to interpret by fellow humans with many surprising pitfalls to keep in mind. It doesn't mean that Ruby doesn't have any pitfall, but at least its community is using this low level of suprise as a guiding principle. Optimizing for the shortest encoding string is missing the point that the biggest cost will be how much time some human being will need to understand correctly what was the intended result. Python used to emphase easy to read over syntax tersrness golf. Looks like it changed. Now, they are people who love that kind of golf, I'm sure. So for them, that's certainly good that Python is digging that rabbit hole. It's ok not everyone share the same taste, isn't it?
- CivBase 1y ago16/26 I always use a reference when doing anything non-trivial with format strings of any kind and this quiz confirmed I should keep doing that. Also I've been using Python professionally for over a decade but TIL about the Ellipsis object.
- neoden 1y agoHow can I setup a linter to prohibit stuff like this in my code base?
- hackyhacky 1y agoJust use Python 3.5.
- jwilk 1y agostr.format() can be cursed too, e.g.: >>> '{:{}{}}'.format('m', 'o<2', 3) 'moooooooooooooooooooooo'
- serf 1y agothe reward for 100% should be a directory of languages that deals with strings in a sane/singular/readable way. it's cool that half of those features are there. it's not cool that half the devs that read the thing after creation are going to have to look up the f string features.
- Y_Y 1y agoI've compiled a directory of those lamguages here:
- nojs 1y ago> This is the first special feature of f-strings: adding a trailing equals sign lets you print out the expression and what it evaluates to. >>> foo='bar'; print(f"{foo=}") foo='bar' Wow, never knew you could do that.
- black_puppydog 1y agosuch a boon for print(f) debugging. :)
- jszymborski 1y agoNo more will I have to print("foo", foo)
- ck45 1y agoPython release notes are really worth reading, for me there's usually some "positive surprise" The = support was added in Python 3.8: https://docs.python.org/3/whatsnew/3.8.html#f-strings-support-for-self-documenting-expressions-and-debugging https://docs.python.org/3/whatsnew/3.8.html#f-strings-suppor...
- lillecarl 1y agoIf you come from verbosity land C# release notes are magically good as well, always some way to reduce boilerplate while maintaining "implicit verbosity" which your proprietary LSP resolves 100% correctly. I'd prefer writing C# if I had the Linux interaction libs Python has. I'm too dumb to write syscall wrappers
- ahartmetz 1y agoIncredibly common for debug output. In C++, I have made it a habit to just copy the expression, once with quotes and once without. It's informative and doesn't require thinking, or, well, I'm still working on that.
- stkdump 1y ago
- stephenlf 1y agoMuch easier than date.wtf
- ciupicri 1y agoFrom JavaScript i.e. https://jsdate.wtf/ https://jsdate.wtf/ ?
- ejiblabahaba 1y agoLearned a few tricks that I'm sure are buried on fstring.help somewhere (^ for centering, # for 0x/0b/0o prefixes, !a for ascii). I missed the nested f-strings question, because I've been stuck with 3.11 rules, where nested f-strings are still allowed but require different quote characters (e.g. print(f"{f'{{}}'}") would work). I guess this got cleaned up (along with a bunch of other restrictions like backslashes and newlines) in 3.12. F-strings are great, but trying to remember the minute differences between string interpolation, old-style formatting with %, and new-style formatting with .format(), is sort of a headache, and there's cases where it's unavoidable to switch between them with some regularity (custom __format__ methods, templating strings, logging, etc). It's great that there's ergonomic new ways of doing things, which makes it all the more frustrating to regularly have to revert to older, less polished solutions.
- sfoley 1y agoYeah I consider that one to be a trick question. I knew same-quote-style nested f-strings were coming, I just didn't know which version, and I still use the `f'{f"{}"}'` trick because I want my code to support "older" versions of python. One of my servers is still on 3.10. 3.11 won't be EOL until 2027.
- zahlman 1y ago> I guess this got cleaned up (along with a bunch of other restrictions like backslashes and newlines) in 3.12. Yes: https://docs.python.org/3/whatsnew/3.12.html#whatsnew312-pep701 https://docs.python.org/3/whatsnew/3.12.html#whatsnew312-pep...
- ctoth 1y agoOne thing I keep not understanding is I see colleagues or AIs put f-strings in logger calls! Doesn't the logger do lazy interpolation? Doesn't this lose that nice feature?
- mixmastamyk 1y agoYes, but won’t matter unless in a tight loop. I usually use % with logging but once in a while use f’’ if easier or needed for some reason.
- jdranczewski 1y agoI usually refer to https://pyformat.info/ https://pyformat.info/, which doesn't have all this detail, but most of the reasonable stuff is included
- jvdvegt 1y agoWhy would "0^5" evaluate to 5? (question 21) And is there a way to link to a specific question?
- andrewfurey2003 1y agoxor
- palotasb 1y ago^ is the XOR operator, 0 XOR 5 is 5. (Exponentiation is *) https://docs.python.org/3/library/operator.html#mapping-operators-to-functions https://docs.python.org/3/library/operator.html#mapping-oper...
- teddyh 1y agoExponentiation is ** or pow()
- procaryote 1y agoOne can question why python needs N built-in ways to printf with different syntax, different ways to escape things and different footguns.
- 6thbit 1y ago“ There should be one-- and preferably only one --obvious way to do it.” — Zen of Python
- pansa2 1y ago> many recent Python extensions seem features in search of use cases […] The real problem with Python, of course, is that its evolution is largely driven by narcissism, not user feedback. Mark Lutz https://learning-python.com/python-changes-2014-plus.html https://learning-python.com/python-changes-2014-plus.html
- lyu07282 1y ago> its evolution is largely driven by narcissism, not user feedback Let's not psychoanalyze Guido
- deleted 1y ago[deleted]
- zahlman 1y ago> why python needs N built-in ways to [do something where there should ideally be only one obvious way] It's the same every time: because some people are unsatisfied with the existing ways and want new ones added, but other people will rain fire and brimstone if you remove the old ones. (BTW: the exact — non-obvious — way the dashes are placed for that line of the Zen is apparently a deliberate joke.)
- lillecarl 1y agoI really like the f"{ varname = }" syntax, didn't know about it before. I have so much Python to learn, I scored 10/26
- Ezhik 1y agoI learned a bunch of these when trying to make an f-string-like library for Lua [1], but `f"{...}" and the walrus ones caught me off-guard. Glad this is nowhere near Wat [2], though. [1]: https://ezhik.jp/f-string.lua/ https://ezhik.jp/f-string.lua/ [2]: https://www.destroyallsoftware.com/talks/wat https://www.destroyallsoftware.com/talks/wat
- variadix 1y agoThat library looks awesome
- Timwi 1y agoThere are many mistakes in the Wat talk from destroyallsoftware. The biggest one is that he types `{}+[]` and claims that he's adding an object and a list. It's actually an empty scope followed by a unary + applied to a list. You can convince yourself of that by noting that `({}+[])` gives different output. A smaller mistake that I find nonetheless amusing is that he uses Array(16) hoping to get 16 string separators. Oops, off by one error :)
- Ezhik 1y agoArguably that first one is just substituting one Wat for another.
- travisgriggs 1y agoWill there be a companion Tstrings.wtf at some point?
- davepeck 1y agoHah! T-strings use the exact same syntax as f‑strings, but their “format spec” (the part after the optional :, like .2f) can effectively be anything. That might make creating a quiz tricky? With f‑strings, Python immediately calls format() on that spec; with t‑strings, it's simply captured in Interpolation.format_spec. It's up to your code to decide whether to call format() or do something entirely different with this value.
- tomrod 1y agoGlorious. I learned a ton, and mostly more than the basics of formatting (something I've never spent a heap of time on). Well done.
- Twey 1y agoAs someone who hasn't written Python in anger since before f-strings were a thing, I correctly guessed almost all the f-string specific syntax but made a bunch of errors that were just to do with the return values of various expressions. Maybe f-strings are the least wtf thing about Python? :)
- pansa2 1y agoDespite the URL, I’d only consider a few of these to be WTFs. Questions 20 & 21 definitely are, though: >>> a = 42 >>> print(f"{a:=10}") 42 >>> print(f"{(a:=10)}") 10 I still can’t believe anyone thought the walrus operator was a good idea.
- almostgotcaught 1y agothis has nothing to do with the walrus operator and everything to do with how string.format works in python https://docs.python.org/3/library/string.html#format-string-syntax https://docs.python.org/3/library/string.html#format-string-... Edit: someone downvoted me because they don't understand there is no walrus operator here print(f"{a:=10}")
- lyu07282 1y agoThey obviously meant the second example: >>> print(f"{(a:=10)}")
- almostgotcaught 1y agothe output of the second example is "obvious" so i don't see the problem.
- pansa2 1y agoNeither of the examples is problematic on its own; it's the fact that the language supports both of them. They're very hard to distinguish at-a-glance yet behave entirely differently.
- sfink 1y agoYou can pry the walrus operator from my cold dead hands. m = re.match(pattern1, line) if m: do_stuff(m.group(1)) else: m = re.match(pattern2, line) if m: do_other_stuff(m.group(2)) else: m = re.match(pattern3, line) if m: do_things(m.groups()) else: m = ... Obviously, there are ways to improve this particular example without using the walrus. But it's also usually not this simple. I run into something like this all the time. Not many times per program, and I don't actually use the walrus all that often, but when it's the right thing it's so very nice.
- jan_Sate 1y agoWoah. That's tough. I scored 12/26. I'm surprised to find that there're so many feature of f-string that I've never heard of. I don't think I'm gonna use them any time soon but nice to know about that.
- noisy_boy 1y ago16/26 I rarely code in python but thought I knew f-strings well - evidently I don't. I am still thinking in 3.6 mode.
- ziml77 1y agoI don't really think there's anything "wtf" worthy about this. A lot of it isn't even about f-string behavior but about the "mini-language" for str.format()
- 0cf8612b2e1e 1y agoThere were a few wats in there, but I agree that most of the test was if you know all of the string formatting syntax.
- recursivecaveat 1y agoI got 20/26. Only ones that really got me were walrus syntax collisions, the types with weirder padding behaviour, some format specifiers I wasn't familiar with. A lot of these are more trivia than wtfs, but not a bad quiz.
- cdaringe 1y agoThis is a nice analog to the JS WAT vid [1] of 2012 [1] https://www.destroyallsoftware.com/talks/wat https://www.destroyallsoftware.com/talks/wat
- va1a 1y agoFun video, you can really feel the 2012 in it too.
- elternal_love 1y agoOh am I writing python code for some years this should be fun ... oh. Oh I see. Hmm. Ok, just give it to me: are they turing complete yet or do we need to wait for 3.14?
- zahlman 1y agoThey've been Turing-complete since they were introduced: $ py3.6 >>> def arbitrary_code(): pass ... >>> f"{exec('arbitrary_code()')}" 'None' >>>
- cvoss 1y agoI think the feature bloat here has passed the break-even point where no one person needs all this, and it takes so long to find what you need in the docs, and you can't be expected to memorize it, because it's so rare to need to use it, and you can't reliably reverse-search the esoteric syntax you encounter, that any given dev is going to take the path of least resistance and write their own routines for this stuff. Pad left? That's a two-line method at most. Versus trying to remember whether the syntax is x:n< or x:<n or what. It's faster to do it yourself ad-hoc. And if the next dev has a question about how it works, the implementation is right there (and easy to customize!) not buried in the docs and immutable.
- al_borland 1y agoI find that weird stuff is often used a lot in a single code base, or it’s not used at all. Solve it once, and copy/paste it every other time you need it in the future.
- dvdkon 1y agoI'd take the middle road, provide a pad_left/pad_right function or method with keyword arguments for specifying things like the padding character. With how often I need to pad some string (often but not every day), this would be my favourite solution. The standard library having no solution of its own is how you end up with JavaScript and every project reimplementing their 10% of a proper standard library, only slower and with more bugs. Though I won't probably use Python's </>/^ format modifiers in my project, I could maybe see them working out in some software that frequently outputs "monospaced" text. In a particular niche, what we think of a needless character-pinching might be seen as a crucial feature and used daily.
- zahlman 1y ago> Pad left? That's a two-line method at most. The functionality comes from the prior string.format method, which has been around since Python 2.6 (first released in 2008). https://docs.python.org/2.6/library/string.html#formatspec https://docs.python.org/2.6/library/string.html#formatspec > It's faster to do it yourself ad-hoc. I have found the syntax to be quite mentally "sticky". > the implementation is right there (and easy to customize!) not buried in the docs and immutable. There are hooks to customize it.
- actinium226 1y agoOof, I got 14/26. I thought I knew f strings fairly well!
- rossant 1y ago15/26 despite nearly 20 years of Python. Should I be ashamed? (Granted, I’ve used it a bit less since f-strings became widespread)
- jasonm23 1y agoprint(f"{f"{{}}"}") - Syntax error... eval it.
- quotemstr 1y agoHalf of these are downstream of the design choice of using { instead of TypeScript-style ${ to delimit expressions.