11 ms·
What the Fuck Python
- deleted 1y ago[deleted]
- alabhyajindal 1y agoPreach. We need more Python slander. It annoys me to no end when people trash JavaScript as if it was some exception in bad language design. Most languages have something bad that can be picked up and trashed on - some more than others.
- heavenlyblue 1y agoGiven that it starts with a thing called "id" which is an implementation detail and probably should not be used for equality, it seems like this is a geniuinely well designed language :)
- mirashii 1y agoid is not an implementation detail, it's a core built-in function of the language. The value that it returns is an implementation detail, but the properties of the value it returns are not and perfectly valid to rely on.
- 0xDEAFBEAD 1y agoThe "properties of the value it returns" are, by design, implementation-dependent. You're only supposed to use the id function if you need to know something about what's going on under the hood. The id function is working exactly as intended: it's exposing aspects of the implementation, if for some reason you need to know that stuff. It would not be a positive change to sacrifice Python performance in order to make the output of id() more intuitive. I've spent many hundreds of hours coding Python and I don't believe I ever used that function or saw someone else use it.
- zahlman 1y ago`id()` is documented and mandated to exist, and the result provides guarantees that make it suitable for identity (not equality) checks[1] (although of course you should normally use the `is` operator). Pitfalls involving it are generally really pitfalls with understanding object lifetimes[2]. [1]: https://docs.python.org/3/library/functions.html#id https://docs.python.org/3/library/functions.html#id [2]: see e.g. https://stackoverflow.com/questions/52096582 https://stackoverflow.com/questions/52096582
- bnchrch 1y agoThank you! For years Ive been saying the sheer volume and fury by which Javascript is criticized is much more applicable to Python. Both aren't perfect languages, and both are far from "the best" but it is maddening that Python get often picked as a darling when its implementation, ecosystem and tooling are fundamentally at odds with correctness and productivity.
- verbify 1y agoI think people pick on js more because it's the only option for scripting frontend for the web, while if you don't like python there's probably another language that can be used instead.
- dreamcompiler 1y agoUnless you're doing AI, in which case you're royally screwed.
- socalgal2 1y agoI'd say people pick on JS because they don't learn it. They jump in, use it like python or C++, get frustrated it's not the same as what they're used to, vow to use it as little as possible. This was especially true before es5/es6 with var function scope and no class syntax.
- moffkalast 1y agoYeah python deserves a good bashing as well, it's about as bad as JS in this regard. I mean for bool("false") resolves to True ffs.
- bnchrch 1y agoDon't forget its transitive dependencies creating non-deterministic builds
- 3eb7988a1663 1y agoThat is entirely consistent with how truthiness works in Python. The function does not claim to parse strings, that is how you get YAML Norway. Do you think there should be different results for bool("no"), bool("false"), bool("heckno!"), bool("heckyes!")? Edit: should have included internationalization: bool("nein!")
- moffkalast 1y agoHonestly once you really think about it just about nothing about these decisions ever makes any real sense which is why JS is made fun of constantly. It's nonsense functions running on nonsense data. "if some_non_bool_value:" should not be valid syntax and truthy and falsy is a concept that would get you locked up in an asylum if you decided to explain it to a doctor.
- crazygringo 1y ago> The function does not claim to parse strings But it's entirely reasonable to think it would. I honestly don't understand why it wouldn't, because: >>> int("35") 35 >>> float("3.5") 3.5 >>> bool("False") True If casting from a string to a type works with ints and floats, why not with bools? What possible justification is there? And of course it doesn't need to work for "no" or "heckno!", that's silly. But it sure seems like it ought to work on whatever the official string representation is. And not produce: >>> bool(str(False)) True I'd honestly much prefer bool() threw an exception on receiving a string, rather than act the way it does now.
- 1y ago
- motorest 1y ago> We need more Python slander. It annoys me to no end when people trash JavaScript as if it was some exception in bad language design. Python's file system support across platforms is notoriously problematic or even outright broken. Wasn't this enough reason to put it lower in the quality bar than JavaScript?
- akdor1154 1y agoJavaScript doesn’t even have file system support.. each runtime has its own tacked on implementation in the relevant “standard” library. Now which is notoriously problematic?
- fragmede 1y agowat https://www.destroyallsoftware.com/talks/wat https://www.destroyallsoftware.com/talks/wat
- bb88 1y agoI came here to say that. That was an eye opening intro to Javascript for me.
- throwaway314155 1y agoJavaScript is far more jarring than Python depending on your background. They do both have issues of course, but that's the reason JavaScript gets "picked on" more.
- bb88 1y agoHow does this attract more people to hackernews who come from the python world? If anything, it just shows how toxic people can be on this site.
- hamstergene 1y agoThere could be generational gap here: for many people the first JS was ES5 or later, which is after the language was taken seriously and fixed. The difference between Python2 and ES1-ES3 was much bigger than between modern Python and modern JavaScript, so some protest against old bad fame is understandable. But, if you have any suspicion that JavaScript has been treated unfairly: it hasn't. It is literally being replaced by TypeScript as we speak. The fact you have to invite people to come up with more Python slander is itself a testimony, JavaScript has never needed an invitation. Having lot more issues than others is what being exception means, and JavaScript is one.
- ltbarcly3 1y agoHaha these aren't even wtfs! the id changes or not? oh noooo, people use the id() function so much, I've literally seen it 0 times ever in production code. This is nothing like the JS wtfs where there is no way to predict what it will do, and it violates it's own patterns. edit: to be more clear, I have run into a lot of JS wtf's trying to write code for work. you just run into bugs all the time where JS doesn't do anything like what would be the obvious thing to do, or the thing that works 99.99% of the time fails depending on the value of the string being 'magic'. with Python I rarely if ever learn some bizarre arcane thing accidentally because it almost always behaves as expected. If you think there's an equivalence here you are just a JS fanboy, JS was a language that evolved largely because of hacks vendors put in and those insane hacks got standardized because it was too late, despite being insane. Python was specifically and carefully designed to minimize unexpected behavior.
- andy_ppp 1y agoI think they are pretty bad tbh apart from the ID one. Everyone knows about the JS quirks so I think it’s good to know sometimes equality in Python strings can behave extremely strangely and the other issues mentioned. Why does it have to be defended “my language is better than your language”? However I’d like to say Elixir is near perfect, thanks :-)
- ltbarcly3 1y agoNo you misread it, equality for python strings works exactly the way you expect. the id() value (which is basically the memory address) might not change if you concatenate strings, but literally nobody ever uses id for anything ever. You would use hash() which does change appropriately. edit: 'wtf!' is always equal to itself. Maybe you are thinking of `is`, which just compares the value of id(). `is` can't be used for comparisons, saying it's a WTF is just being unfamiliar with basics. `is` is not used for equality comparisons. This is how more or less every language works, comparing pointers is not the same as comparing strings in C/rust/etc. Comparing object identity is not the same as testing equality in Java.
- 1y ago
- JohnKemeny 1y agoIf you use a floating point number as a key in a `dict` the wtf should not be pointing at Python. These are not wtfs, please. These examples read like someone who is learning to program and who is confused. x is not y x is (not y) How can you confuse these two?!
- mvanbaak 1y agoAI
- deleted 1y ago[deleted]
- woooooo 1y agoFp32 or fp64 in a strongly typed language would be no problem as hash keys. Yes, they're imprecise for math but the 64 bits of data should work just like a long as a hash key.
- marcosdumay 1y agoNo, they are not suitable for use as hash keys unless you are treating them as opaque binary data. And if you are there, you are better putting your values in some type that means opaque binary data for the start.
- spacechild1 1y agoThey are perfectly suitable as long as you know what you are doing. Here's a real use case: when compiling a scripting language, map float constants to slots in a "constant table" so that all constants with the same value share the same slot.
- zahlman 1y agoIf they are actually compile-time constants and you never have to deduce the value by a runtime calculation, then that is exactly what is meant about treating them as opaque data. Otherwise, prepare for the horror of realizing that `{0.3: 'test'}[0.1 * 3]` (or the syntactic equivalent) fails — in every programming language that lets you try.
- LPisGood 1y agoSome of these just seem to be using Python out of spec and being surprised that implementation details exist, and misunderstanding boolean expressions.
- otabdeveloper4 1y agoPython doesn't have a spec. It barely even has documentation nowadays. (Sad. Twenty five years ago it was the gold standard of documenting software.)
- troupo 1y ago> Twenty five years ago it was the gold standard of documenting software. That was PHP. Though Python was a close second
- LPisGood 1y agoI don’t understand what you mean by “doesn’t have a spec” The existence of Pypy and CPython and separate but compatible entities shows that there is
- motorest 1y agoCPython is the de-facto reference implementation of Python. Pypy was developed by reverse engineering CPython and their automated tests feature explicit comparisons with CPyton. You made the opposite point you thought you were making.
- librasteve 1y agoin raku, the test suite (ROAST) is the spec any compiler that can pass ROAST is valid
- simonw 1y agohttps://docs.python.org/3/reference/grammar.html https://docs.python.org/3/reference/grammar.html and https://docs.python.org/3/reference/index.html https://docs.python.org/3/reference/index.html look pretty comprehensive to me, and they're backed up by a thorough collection of PEPs: https://peps.python.org/pep-0000/ https://peps.python.org/pep-0000/ As a relatively recent example, here's the language reference documentation for the match statement https://docs.python.org/3/reference/compound_stmts.html#the-match-statement https://docs.python.org/3/reference/compound_stmts.html#the-...
- omoikane 1y agoSee also: https://github.com/satwikkansal/wtfpython https://github.com/satwikkansal/wtfpython The "interactive notebook" link goes to the colab page. There are many earlier threads associated with the markdown version, for example: https://news.ycombinator.com/item?id=21862073 https://news.ycombinator.com/item?id=21862073 (2019-12-23, 185 comments) https://news.ycombinator.com/item?id=26097732 https://news.ycombinator.com/item?id=26097732 (2021-02-11, 163 comments) https://news.ycombinator.com/item?id=31566031 https://news.ycombinator.com/item?id=31566031 (2022-05-31, 143 comments) https://news.ycombinator.com/item?id=37281692 https://news.ycombinator.com/item?id=37281692 (2023-08-27, 82 comments)
- rr808 1y agoWhile we're at it. Notebooks aren't a real programming environment.
- incognito124 1y agoI don't think anyone is disputing that
- klysm 1y agoHuh we must be hallucinating then?
- rexpop 1y agoYeah, this simply doesn't work for me; ie the expressions did not evaluate, and output was not made visible. I have never had a successful experience writing or running programs in notebooks like this--although I have not, arguably, tried with high stakes. As soon as the stakes rise that far, however, I reach for a whole-ass Unix environment with a shell, a filesystem, and a stateful process model. Is this a crutch? Is it too much overhead? It's arguably absurd that I even ask. (Edit: It's actually killing me how ambiguous I'm being, right now. There's no winning.)
- zahlman 1y ago> As soon as the stakes rise that far, however, I reach for a whole-ass Unix environment with a shell, a filesystem, and a stateful process model. I don't understand what you mean by "reach for". Don't, for example, Linux desktop users have all these things at hand all the time? For me it would take much more effort to set up a "notebook" than a virtual environment.
- fragmede 1y agoFor you, sure, but for someone that lives and breathes notebooks, running jupyter notebook and going to localhost:8888 already happened, so it's opening a terminal that's the extra step.
- 1y ago
- Danjoe4 1y agoWho writes python this way? Good Python code, being such a flexible language, relies on conventions. Never seen the id() function in production code. "Is" is canonically used for "if var is None", not string comparisons. Python has a rich library of string methods, maybe use them? You're finding bugs because you're using the language like a QA tester instead of the way its intended. If I saw string_var is "some_string" in a PR, I would reject it. Even the triple boolean comparison example should just be separated with an "and". Read PEP20 and PEP8. A goal of Python is to be as readable as possible, not to conform to some spec. You may not agree with that design decision, but all these examples have an obviously more readable alternative which would work. Jeez. It's like me complaining that Rust looks ugly (it does). The language was designed with a different set of priorities.
- deleted 1y ago[deleted]
- motorest 1y ago> You're finding bugs because you're using the language like a QA tester instead of the way its intended. What do you think this means? Are the bugs there or not?
- fragmede 1y agoNot all bugs are equal though, and if I'm only going to run across the bug when I'm standing on my head the third Wednesday of the month while singing Poker Face, it's a bit less concerning than one that happens only on days that end in "Y".
- happytoexplain 1y agoSo we shouldn't learn about them? They're offensive to enumerate? No, they're useful to understand.
- fragmede 1y agoSo we should put them into the bug tracking system and prioritize them accordingly. They're very useful to understand, but if one costs $100 every time it happens but it only happens once a year, vs a different bug that costs $1 every time it gets hit, but it happens every day, which one should get fixed first?
- hansvm 1y agoThe first third of this seems to just be complaining that it's not obvious when two objects are actually the same object, and that if you mistake identity-related operators for other operators then you'll have a bad day. That's a fair critique. It's a little weird that `is` and friends have dedicated, short, nice syntax. On the other hand, most compiled languages are compatible with an implementation which admits the following optimization: const a: u32 = 42; const b: u32 = 42; assert(&a == &b); The language usually doesn't guarantee that different immutable variables have dedicated memory on the stack, or that they even live on the stack in the first place. That's the same class of error we're seeing here, and even among popular interpreted languages Python is by no means unique. I might get to the bottom 2/3 of the doc later, but the rest was off-putting enough that I don't know I'll bother.
- hmry 1y agoYeah, it would be much clearer if instead of an `a is b` operator, there was a `same_object(a, b)` built-in method.
- procaryote 1y agoI'm happy to complain about python but I got like a third into it and didn't find any actual wtfs. Java as contrast has interning wtfs because == between java objects does essentioally what python's `is` does. Python actually made a good choice here and made == do what you'd expect. Is anyone surprised by `(1 > 0) < 1`? There are languages where it will be rejected because of types, but what else would you expect it do than compare a boolean true to 1? Is there anything of value later on?
- zahlman 1y ago> Is anyone surprised by `(1 > 0) < 1`? This is presumably meant as a setup for the fact that the result of `1 > 0 < 1` differs from the result with parentheses set up either way (because this is a chained comparison), and furthermore that such chained comparisons are legal even when they don't have the operators all "pointing" the same way (like in mathematical notation). And that operators like `in` and `is` are allowed to participate in this system on equal footing.
- bb88 1y agoI think there's a few in there. But most people aren't going to write code that way. It's good to know, and keep in your head, but if you have to think too hard in the future if a piece of code is correct, it's probably better to rewrite it anyway. And weird code like that shows up like a sore thumb in reviews.
- never_inline 1y ago> Java as contrast has interning wtfs because == between java objects does essentioally what python's `is` does. It's pretty sensible because i wouldn't expect that operator to call a method - since Java does not have operator overloading.
- procaryote 1y agoYeah, it's not that bad, but `if foo == "bar"` or `foo == Integer(someInt)` looks reasonable, and worse, sometimes works
- happytoexplain 1y agoI'm a little flabbergasted at how many comments here boil down to "These aren't WTFs if you understand the language."
- pseufaux 1y agoIt's a bit like when non-JS programmers complain about JavaScript. It's mostly nonsense. That's not to say that JavaScript doesn't have flaws and footguns, but the opinion of novices in the language is not who I am interested in learning from. Python is the same. It has flaws and idiosyncrasies, especially in the standard library (cough cough xml.ElementTree), but the core language is fairly consistent and predictable. Expecting casting functions like bool() to parse strings like JavaScript does makes little sense.
- evanjrowley 1y agoNow do a "What the Fuck Excel"
- throwaway2037 1y agoGood point. The "snap to zero" rules are wild in Excel.
- ssalazar 1y agoI didnt make it past the long list of id() misuses, but its a rookie mistake to confuse referential equality with value equality, and when doing so youre in for a bad time.
- zahlman 1y agoThe point is not simply about the existence of a separate concept of object identity; it's about the details in the circumstances in which Python creates separate-but-equal objects rather than reusing the same one.
- harrisi 1y agoI'm surprised by the reactions to this. It's made immediately clear in the notebook that this is a fun look at some interesting behaviors of Python. There's no implication that there are bugs - I have no idea where anyone got that idea - except for the single actual bug in CPython that is mentioned (https://github.com/python/cpython/issues/54753 https://github.com/python/cpython/issues/54753). I don't feel strongly about Python, but I do think CPython is a great way for people to learn a bit about how interpreted languages work. The code is quite easy to understand, and you can easily play with these interesting aspects of how languages and runtimes work. Does every Python programmer need to know the difference between `a = 256` and `a = 257`? No. Is it interesting? Yes. Should someone on your team know? Probably. There's a lot of interesting stuff here. Understanding the difference between the conceptual idea of each line of code and what actually happens is fun, and, in some cases, important.
- msgodel 1y agoIt probably wasn't a good idea to start it out is showing string constants aren't optimized. If they wanted to talk about really unintuitive reference gotchas initialization in optional function parameters would have been a way better example.
- harrisi 1y agoI appreciate the sentiment, but even this is a good example of why this stuff is interesting. Because some strings _are_ optimized (using some definition of "optimized"), but only in some cases. It's these quirky little things where the code doesn't exactly represent the way execution happens in most straightforward mental models of how execution works. Again, it's not bad and it's not unique to Python. It's just the nitty gritty of how some things work. I will say that calling it "What The Fuck Python" is certainly more attention-grabbing than "Some Interesting Bits About Python Internals You Probably Don't Need To Know". What're you gonna do. :)
- msgodel 1y agoI don't know I think "Python doesn't optimize <x>" is one of the least surprising classes of statements in programming.
- sundarurfriend 1y agoAside: In the process of submitting this, I learnt that Hacker News apparently has an anti-censorship title transform built-in. I submitted it with the title taken from the notebook - "What the f*ck Python!" - and HN automatically removed the ! and changed "f*ck" to "Fuck".
- g42gregory 1y agoI may be wrong, but think a lot of it is undefined behavior. Interpreter may choose to recycle objects or it may not. In case of integers, low enough number in different parts of the program, will be represented by the same object. But if the integer is high enough, different objects will be created. That’s my understanding, but I could be wrong.
- zahlman 1y agoThe behaviour is implementation-specified or unspecified, but not undefined. You will not unleash https://catb.org/jargon/html/N/nasal-demons.html https://catb.org/jargon/html/N/nasal-demons.html this way.
- ValveFan6969 1y ago[dead]
- globalnode 1y agoSome ways of programming in Python require a LOT of mental effort. And some don't. For example you can do a lot in one line in Python, but I usually have to write extensive comments and references to external docs to keep track of what that one line is doing. I think sometimes it would be easier if I just had to write 3 or 4 lines of self evident code and use that as docs instead.
- bb88 1y agoHaving written python professionally for more than a decade, I highly recommend not writing complex one-liners -- unless there's some real benefit to doing so. The more one-liners there are in the code base, the more impenetrable and harder to debug the code is. Unrolling nested functions and switching comprehensions to lists and if statements often make it cleaner and easier to write unit tests for. If you rely upon code coverage for unit tests, a complex list comprehension won't help you see if you have hit the branch cases.
- throwaway2037 1y agoPersonally, I always find multi-layered list comprehensions the hardest to read... And debugging list comprehensions is basically impossible in my experience.
- never_inline 1y agoUse static types and treat python as more concise java. Use dynamic types sparingly. Limit expression complexity. Static types + IDE features make it much easier to understand any codebase.
- hislaziness 1y agoGreat. I enjoy these kind of articles. My all time favorite book for 'C' is Expert C Programming: Deep C Secrets.
- pyuser583 1y agoExclamation points are in fact part of the ASCII standard.
- pansa2 1y agoMy favourite Python misfeature is that `x += y` sometimes does the same thing as `x = x + y` and sometimes doesn't. This leads to minor WTFs like this: >>> a = b = (1, 2) >>> a = b = (1, 2) >>> a = a + (3, 4) >>> a += (3, 4) >>> b >>> b (1, 2) (1, 2) >>> a = b = [1, 2] >>> a = b = [1, 2] >>> a = a + [3, 4] >>> a += [3, 4] >>> b >>> b [1, 2] [1, 2, 3, 4] And major ones like this: >>> a = ([1, 2], ['one', 'two']) >>> a[0] += [3, 4] TypeError: 'tuple' object does not support item assignment >>> a ([1, 2, 3, 4], ['one', 'two']) The operation raises an exception even though it succeeds!
- GeneralMayhem 1y agoYour first example has to do with the fact that tuples are copied by value, whereas lists are "copied" by reference. This is a special case of an even larger (IMO) misfeature, which is that the language tries very, very hard to hide the concept of a pointer from you. This is a rampant problem in memory-managed languages; Java has similar weirdness (although it's at least a bit more consistent since there are fewer primitives), and Go is doubly odd because it does have a user-controllable value vs. pointer distinction but then hides it in a lot of cases (with the . operator working through pointers, and anything to do with interfaces). I think the whole thing does a misservice to novice or unwary programmers. It's supposed to be easier to use because you "don't have to worry about it" - but you really, really do. If you're not familiar with most of these details, it's way too easy to wander into code that behaves incorrectly.
- pansa2 1y ago> Your first example has to do with the fact that tuples are copied by value, whereas lists are "copied" by reference. My mental model for Python is that everything is '"copied" by reference', but that some things are immutable and others are mutable. I believe that's equivalent to immutable objects being 'copied by value' and mutable ones being '"copied" by reference', but "everything is by reference" more accurately reflects the language's implementation.
- zbentley 1y agoIt’s reassuring that a lot (feels like a majority) of these are noted as resolved or turned into errors that make more sense than confusing behaviors in later editions of the language. Python 3.5, which is what the WTFs use by default, is relatively ancient.
- satwik 1y agoHi, author of the repo (https://github.com/satwikkansal/wtfpython https://github.com/satwikkansal/wtfpython) here, pleasantly surprised to wake up to this thread about it. The intention of the project is not to put Python in a bad light relative to other languages, the intention was to explore it more deeply through (sometimes contrived) snippets that give non-obvious outputs. I believe for a regular Python programmer, the "Slippery Slopes" section is a must-know. The first section (Strain your brain), does contain some patterns that you may not ever see in real world, the goal there is to just learn about internals. Agreed some of them are very obvious for a well-learned programmer, and some of them aren't even Python specific, it does help a lot of beginner to intermediate programmers. I remember it being given as a supplementary material in one of the CS-based course. It is curated with something-for-everyone approach, I expect people to learn a thing or two about Python / CS after going through the snippets. I haven't updated it in a while in a major way, but looking at the feedback I'll try to organise them better, and add new snippets (I have a long personal list that I maintain) in a future release!
- meander_water 1y agoThis is great. Also to be a little meta, this link was posted in 2019 (https://news.ycombinator.com/item?id=21862073 https://news.ycombinator.com/item?id=21862073) and got the same sort of comments (how js gets flak, and python doesn't)
- timonoko 1y agoSmall numbers are "eq" in python. It saves space and time, because probably those numbers dont even exist, and the value is derived from the pointer value. >>> a=3 >>> b=3 >>> a is b True >>> a=1e20 >>> b=1e20 >>> a is b False But in Commonlisp all numbers are "eq". Very strange. Is there heap of numbers and once created, they reuse those? [4]> (setq b 1E20) 1.0E20 [5]> (setq a 1E20) 1.0E20 [6]> (eq a b) T
- Jtsummers 1y ago> But in Commonlisp all numbers are "eq" No, that's not true. >> numbers with the same value need not be eq, http://clhs.lisp.se/Body/f_eq.htm#eq http://clhs.lisp.se/Body/f_eq.htm#eq It's not guaranteed that eq will return true for two numbers of the same value in Common Lisp. It happens to work much of the time, but it is never guaranteed to work. For a given implementation it could even be true all the time (as it's not disallowed), but for portability it should not be relied upon.
- kazinator 1y agoIn Common Lisp, in fact, no numbers are required to be eq! Even (eq 0 0) is not required by ANSI CL to return true. Why your Lisp implementation produces true for (eq a b) is probably because of the following. Firstly, in Common Lisp there are single and double precision floats. Floating point tokens written with E or e are single. An implementation is allowed to map that to a 32 bit float. If the implementation has 64 bit values, it can easily arrange for single precision floats to be unboxed without any special tricks; they need only half the word. Try evaluating with 1D+20 to see what that does. But even 64 bit values can be unboxed with a trick called NAN tagging. I implemented NAN tagging in TXR Lisp (which has only double-precision floats), enabled on 64 bit targets: 64 bit machine: 1> (eq 1E20 1E20) t 2> (sizeof val) 8 32 bit machine: 1> (eq 1E20 1E20) nil 2> (sizeof val) 4 On 32 bits, floating-point objects are on the heap. It's pretty important to have unboxed floats for intense numerical work.
- explain2me 1y agoHolly cow, what a mess. Is the miniscule efficiency gain really worth it especially in such a user friendly language as Python?