Rendered at 06:36:53 GMT+0000 (Coordinated Universal Time) with Cloudflare Workers.
Revanche1367 6 hours ago [-]
A lot of Python design decisions have felt weird and off to me but they’ve long justified it by saying that it’s those little ugly design choices that make the language so usable and effective in practice compared to more well-designed languages that hardly anybody uses. I’m not enough of an expert to clearly say if that’s really true, but imo, there’s a repeated pattern of slightly weirdly designed languages becoming super popular: Python, Javascript, perhaps C as well. Or, maybe we only notice the weirdness because these languages are used so much and get nitpicked to no end.
stephenlf 5 hours ago [-]
Yes. These are funny little quirks, but nobody will ever get tripped up by them.
frollogaston 6 hours ago [-]
JS is a lot less weird than Python. And Python is what I started with and continue to use half the time. The article missed the most common one, __name__ == "__main__" like wtf
Revanche1367 6 hours ago [-]
I’m not a regular JS user and haven’t touched the language in a long time, but I remember a (popular?) website for teaching modern JavaScript mentioned that some aspect of the function/macro that returns the type of an object was just plain wrong in a specific and important case. This was years ago however, so maybe the problem isn’t there anymore. Anyhow, I added JS to the list mainly because it is known as a badly designed language and Brendan Eich seems to agree.
frollogaston 6 hours ago [-]
There are certainly weird things about it, but they're all things you can ignore especially in modern times, whereas in Python you're constantly dealing with it head-on.
Revanche1367 6 hours ago [-]
Totally agreed there, Python is my main language nowadays because of work but the inconsistencies and lack of some very easy to add syntactic sugar to cover up some of the ugliness (like your example above) in a backward compatible way is constantly irksome and keeps me from really loving my most used tool.
lukan 5 hours ago [-]
Ah yes, nowdays it is even easier, but "Javascript, the good parts" came out 18 years ago already.
Helped me get a more pragmatic approach to use that chaotic mess of a language and environment. Just use what works, ignore the rest (but I also ignored some specific advice from the book and used what worked for me).
Daishiman 4 hours ago [-]
I'm not sure what world you live in but I remember quite well when prototypical inheritance was The Way in JS to do object-oriented programming. Then they copied the C#/Java syntax for classes. Then they aded a bunch of reactivity with Observable with a ton of quirks.
Every single new, large feature in JS has been full of quirks. The same cannot be said for Python; the exceptions are few and far between and more often than not they're not actually exceptions but rather something bound to core language fundamentals which once understood don't present a challenge because there is an actual underlying consistency.
frollogaston 39 minutes ago [-]
11 years ago sure. Then the classes they added were syntactical sugar. Observable was never part of JS, it's from the rxjs lib that I avoided cause yeah it's spaghetti.
In about the same timeline, Py went from threading to async-await, which created classic blocking vs nonblocking mismatches. The whole 2 to 3 breaking migration was also still a big deal in 2015.
(Note some of these are outdated, but some of those only mention that towards the end of the section rather than the beginning)
hackyhacky 6 hours ago [-]
> JS is a lot less weird than Python.
I challenge you to find Python behaviors as weird and off-putting as anything here: https://wtfjs.com/
frollogaston 6 hours ago [-]
A lot of those are stuff I'd never do like `Test.prototype = null;`. Some are legit footguns, but they rarely get in your way.
Python has weird file imports (no relative ones either), broken package management, historical differences between asyncio and blocking that still cause issues, threading/GIL caveats that trip up even experienced users, indentation for scope (esp weird given it was designed for REPL), weirdly no anonymous functions, 2 vs 3 (mostly gone by now), the __init__ and __init__.py stuff, namedtuple vs dict vs object, `global`, and a whole mess with type-linting if you're going there. You have to deal with all those things every time.
Here's one little Python footgun that everyone hits and is also annoying after:
def func(array=[]): # default value is empty array, right?
array.append("asdf")
print(array)
>>> func()
['asdf']
>>> func()
['asdf', 'asdf']
Daishiman 4 hours ago [-]
What you put as an example isn't a footgun if you know how the language evaluation rules work. Once you understand that the "footgun" explains a dozen behaviors, which may be a weird behavior but it is consistent.
Izkata 3 hours ago [-]
Which isn't really much of a refutation because you can say the exact same thing about what's on wtfjs.
DangitBobby 3 hours ago [-]
There's really no comparison. I use both languages extensively and JavaScript is by far the quirkier language.
jrrv 5 hours ago [-]
I clicked on half a dozen of these at random and none of them are weird.
For example, why would you expect `Boolean("false")` to equal `false`? It's a string, and bears no relation to the Boolean type. [0]
I agree that the examples on that site are not very good. What about
[1, 2, 3] + [4, 5, 6] == "1, 2, 34, 5, 6"
or
parseInt(0.000001) == 0
parseInt(0.0000001) == 1
or
"" + 5 == "5"
"" - 5 = -5
frollogaston 5 hours ago [-]
A lot of them are also about nulls and == vs ===, which are weird, but they're weird in many langs. Like Python has the whole == vs `is`. You just learn the convention and use it. Same with typecasts.
joaohaas 5 hours ago [-]
What about the fact that there isn't a single 'parseInt' function in JS that can reliably only convert number strings to numbers?
They each have different quirks (some will parse 'a123' as 123, others will handle scientific notation etc). The only reliable way of doing this is doing a regex followed by parseInt... which is definitely a footgun IMO.
Izkata 3 hours ago [-]
Unary "+" returns NaN for strings that don't contain exactly a number (except for empty string which standard type conversion turns into 0). It even works for scientific notation like +'1e3' === 1000.
hahn-kev 5 hours ago [-]
Fair, but I'd expect consistency. Number("1") equals `1` IIRC.
zmgsabst 5 hours ago [-]
> __name__ == "__main__"
What makes this weirder than other languages detecting if they’re an import or an invoked file?
scoofy 30 seconds ago [-]
It’s only weird syntactically. Python tends to lean towards intuitive, natural language by default. I would have assumed they’d have created a syntactically straightforward alternative, like:
__this_file__ == “__launch_file__”
or similar. I understand python values “only one way” of doing things, but it would be helpful for readability.
Python has some absolutely kick-ass libraries, even without C. It has Django, for those of us who like developing web apps but never could fall in love with Ruby on Rails. And Django is amazing. I've also yet to see a better language for writing quick ETL scripts and pipelines. Also, an 'I need a script for $SYSADMIN_TASK but I want to be able to read it later.' Anything dominated by external latencies (web, databases, etc) will be fast enough for many uses in Python.
Sure, it's not a language to write a web browser or game engine in. And it is slow. But it has some very strong niches outside of ML/Data science. Personally, I love it. To each their own.
JodieBenitez 4 hours ago [-]
> Also, an 'I need a script for $SYSADMIN_TASK but I want to be able to read it later
uv + PEP723 make this even better.
nneonneo 8 hours ago [-]
The __debug__ constant is really weird - any block of code guarded with `if __debug__:` will be entirely omitted from the bytecode under PYTHONOPTIMIZE=1. This and `assert` are the only two examples of real “conditional compilation” in Python. This is also the reason why you cannot assign to __debug__: doing so would make it possible to invalidate the compiler’s assumption about `if __debug__:` statements.
plant-ian 8 hours ago [-]
I honestly have never even heard of this constant and I feel like I've been using python for a pretty long time. Although maybe my memory for some things just gets garbage collected if I don't use it enough. Does it actually get used that often in real world code? Seems like it might be kind of risky.
UqWBcuFx6NV4r 6 hours ago [-]
Ditto. I’ve certainly never used it and can’t recall seeing it in any codebases I’ve worked on or looked at. Sounds interesting though!
I’ve of course certainly heard of, seen, and used `assert`, but more often than not, outside of pytest, I see its use way more in potential footgun scenarios—I doubt that many people know that assertions can be silenced, and that they’d probably be better off raising exceptions in many cases where they’re using `assert`.
nneonneo 5 hours ago [-]
I made a CTF problem where `assert` was used as a critical safety check - and where "accidentally" running the program under -O (for speed!) resulted in a security vulnerability. A large fraction of the people who attempted the problem seemingly missed this bug.
I would not be surprised in the least if that pattern existed in the wild. In fact, it's quite common to see this in C/C++ codebases too: people will use assert() to check a security-relevant property, and then disable those checks in their release builds "because it can't happen".
rcxdude 7 hours ago [-]
I feel like it's the kind of thing you might wind up caring about if you're micro-optimizing your python, but in my experience that's a losing game and you're better served rewriting it in another language than bothering with trying to speed up the execution of the raw python code (it's not that you can't optimize python code, but only in broader strokes. If you are looking at the bytecode you're in too deep and every time I've seen it tried the code has been ported shortly afterwards).
Vexs 7 hours ago [-]
I see asserts used in production code as part of flow control way too frequently, so I assume the majority of python users aren't aware of the -O flag, much less this behavior- which I too haven't ever heard of.
Of recently, I've noticed claude is a big fan of asserts too.
UqWBcuFx6NV4r 6 hours ago [-]
Yep. I’ve had to tell Claude to basically not use assert. Thankfully it’s very complaint in this one area.
Numerlor 7 hours ago [-]
If 0. Etc. are also compiled out, at compile time __debug__ is simply False or True and the existing optimization paths take care of it.
Assigning to __debug__ wouldn't do anything to the compiler as it never actually reads the variable, so assignment would just cause weirdness from other use
neillyons 8 hours ago [-]
I remember reading that in early versions of Python there was no built in True and False. Each user would implement this themselves as
True = 1
False = 0
then later these got added to the language. In Python 2 you could still reassign and swap them so that 'if False' was actually true!
True, False = False, True
Python 3 you could no longer reassign them.
Animats 7 hours ago [-]
Misery is trying to retrofit "bool", True/False, and nil/null to a language. C had to do that. Python had to do that. Getting those wrong is one of the classic language design mistakes. It seems like treating "True" as a value that equates to 1 will work, but then the special cases get you. Like being able to perform arithmetic on True.
Common language design boners:
- Not building in strings. That's now in the past. Everybody has strings. (Well, C...)
- Not building in multidimensional arrays of the numeric types. Everything that number-crunches needs them, and having multiple definitions is Not Fun and may lead to expensive re-copying between different libraries.
This is an enormous blind spot in language design. It's one of the reasons FORTRAN, which has good multidimensional numeric arrays, is still often used for number-crunching.
- Not standardizing the small vectors (vec2, vec3, vec4) and their matrix friends. Graphics code depends on these, and it's really annoying if there are multiple slightly incompatible implementations. Especially since GPUs have hardware for those types, and you want CPU and GPU to use the same representations.
- Not having arrays of bits. Pascal had PACKED ARRAY[0..N] of BOOLEAN but that was lost in later languages. It's useful to have that as a language construct, because most modern CPUs have good hardware for dealing with bit strings, and you'd like the compiler to use it.
Most useful languages acquire these features, but, when they come in late, there are multiple similar implementations, and libraries made incompatible by depending on different implementations.
(Amusingly, when Second Life switched from Linden Scripting Language to Luau, they initially had True, TRUE, and true all in use, as different types with different semantics. I was able to persuade the devs to unify the boolean types.)
tialaramex 4 hours ago [-]
You list a few absences but absences aren't the end of the world, I say it's worse when designers make a booboo where the language semantics are wrong. In C++ there are so many of these it's not sporting but a recurring example from the garbage collected languages would be the for-each loop mistake.
Several times now†, people make a language where the way a for-each loop (for each Goose in Geese ...) works is that there's a single variable Goose and each time around the loop we change which value is referred to by the Goose variable. This seems intuitively like a reasonable way to do this. But it's wrong and eventually your programmers will get nasty surprises. What you actually should deliver is an implementation where each time around the loop there's a new variable named Goose, that variable goes away at the end of that iteration and will be replaced by the next one, with the same exact name.
† At least Go and C#, I think there are others
lelanthran 22 minutes ago [-]
> What you actually should deliver is an implementation where each time around the loop there's a new variable named Goose, that variable goes away at the end of that iteration and will be replaced by the next one, with the same exact name.
Is this because a closure inside a loop will capture a reference to `Goose`?
I think that this is a capture problem not a variable problem. The closure should always do the right thing and capture the value of all variables (not just ones inside the loop), instead of capturing the reference to the variables.
Then the general problem is fixed to match what developers expect, instead of a specific instance of that class of problems being fixed and working differently to how other captured variables work.
dwattttt 7 hours ago [-]
> Not having arrays of bits. Pascal had PACKED ARRAY[0..N] of BOOLEAN but that was lost in later languages. It's useful to have that as a language construct, because most modern CPUs have good hardware for dealing with bit strings, and you'd like the compiler to use it.
I'm not sure exactly which features are responsible (I'm inclined to blame templates), but C++'s std::vector<bool> is a rough edge. For those unfamiliar, the standard specifies this vector template in a way that's not compatible with other vectors.
Lvl999Noob 4 hours ago [-]
Agreed. Instead of special casing Boolean arrays to be packed, it's better to have standard Boolean arrays and bitarrays as separate types.
NekkoDroid 24 minutes ago [-]
They should have made `std::bitset<std::dynamic_extent>` what todays `std::vector<bool>` is (actually maybe not, `std::bitset` is fixed sized, just compile time fixed size). While at it also make `std::array<std::dynamic_extent>` a runtime fixed size array.
taylor-tg 5 hours ago [-]
Oh wow, I had no idea that SL did another language change after migrating LSL to Mono. Surprising considering that happened late '00s/early '10s?
I'd consider LSL to have been foundational in my ultimate interest/career in software engineering. The strict typing, very usable compile/runtime errors, and good documentation/examples made it so easy to pick up as a teen. Not to mention as long as you didn't edit/save a script again it would always run the same regardless of updates.
DarkUranium 6 hours ago [-]
Vectors & multidimesional arrays are something I'm 100% adding to my language's core.
It kind of started with vectors as the very first feature (I was sick & tired of libraries reinventing their own `Point`/`VectorN` in incompatible ways).
AdamH12113 6 hours ago [-]
Strings are a really weird data type. I'm not sure you can do much better than C strings without implicitly requiring dynamic memory allocation, which C deliberately does not do.
Definitely agree on multidimensional arrays. I feel like efficient arrays in general are underrated in high-level language design.
tialaramex 5 hours ago [-]
> Strings are a really weird data type. I'm not sure you can do much better than C strings without implicitly requiring dynamic memory allocation, which C deliberately does not do.
The thing you want is what Rust delivers in the box, &str a string slice reference type, in Rust's case the "string" is UTF-8 encoded text. On the bare metal the way to represent this type is as a "fat pointer" typically a pair of registers, one with the address of the first byte of the string and the other with a length.
C should have fat pointers, they were proposed, for IIRC C89 but the proposal was rejected. That's pretty sad, the fat pointer is expensive to the point of maybe feeling extravagant on a PDP-11, but by 1989 that's long gone.
More ridiculously C++ didn't get this type (which it eventually called std::string_view and provides in its standard library not as a built-in) until 2017, years after Rust 1.0 shipped. In the meanwhile C++ just did not have a sensible way to do this, strings are hard apparently.
The string buffer feature, allowing you to actually make strings is less important, as you say it will need an allocator and so on very bare metal you might not have this - but the string slice reference doesn't need an allocator.
I think it's worth delivering the basic "it's a growable array type, duh" implemenation of the string buffer type, which is what Rust's String type is, but C++ chooses to ship an oddly specific small-string optimized version as std::string right from the offset.
jamesfinlayson 3 hours ago [-]
Yes I remember a friend doing university marking for a beginners programming course years ago and some student had managed to swap True and False making their assignment very wonky.
LPisGood 8 hours ago [-]
It is certainly the case that isinstance(True, int) returns True, even today.
Python is awful. There are so many one offs in libraries, none agree on a style, it’s slow, and it’s way too easy to do the wrong thing. I often work with data scientists and have to productionize their jupyter notebooks which is pure suboptimal hell. I guess it must be a good easy learning curve for research/scratchpad
stouset 6 hours ago [-]
I’ll never not be bitter than Python “won” the scripting language war over Ruby, more or less just because someone did a bit of AI work in it first and it took over that space by default.
Ruby has such a nice holistic consistency to it. With a few exceptions, it feels like it was conceived of by one person with a core idea in mind. Python feels like a mess.
hetman 23 minutes ago [-]
Ruby is beautiful in its design, but it made imports and namespaces (a.k.a. modules) separate concepts. This is so flexible it became hard to ever find anything easily in practice.
Likewise, it made classes incredibly easy to extend, which led to a monkey patching bonanza and far too much magic everywhere (Rails being by far the worst offender but not the only one). It meant having to keep too much stuff in your head and needing deep framework/library familiarity just to be able to understand basic code.
In the end, I feel like the incredible flexibility was Ruby's undoing, not just lack of library availability for a specific popular application. I was a Ruby zealot at one point but it began to lose its lustre not because it wasn't beautiful in theory, but because it was inconvenient in practice. In some ways, Python's restrictiveness became its greatest attribute. Then Python 3 helped to fix a lot of the inconsistency.
Both Python and Ruby have a consistent logic to them, just not consistent with each other. Just as all attributes are methods in Ruby, so all methods area attributes in Python, etc. Things get much easier in either language if you stop fighting their internal logic.
Revanche1367 6 hours ago [-]
Long before AI work, numerical data crunching is what Python became popular for among non-computer scientists and this led directly to the AI use cases. The reason was obviously the lower barrier to entry without having a software engineering background. I also share with you that feeling about Ruby in particular.
gucci-on-fleek 5 hours ago [-]
> I’ll never not be bitter than Python “won” the scripting language war over Ruby, more or less just because someone did a bit of AI work in it first and it took over that space by default.
This is just my personal opinion with no data to back it up, but I suspect that Python "won" because it has excellent Windows support, while Ruby doesn't. Even a decade ago, Python's website offered an official native Windows installer [0], while Ruby's website [1] still points you to a third-party installer, which doesn't even have native support since it uses MSYS2 [2].
Most non-developers use Windows, so if you're choosing the first language to teach a large group of people, good Windows support is fairly important. Python being the "default" introductory language gave it a huge number of users, then I suspect that everything flowed down from there.
> but I suspect that Python "won" because it has excellent Windows support, while Ruby doesn't. Even a decade ago, Python's website offered an official native Windows installer
I think you might be able to go an additional decade backwards. Back in college most of my friends were on windows and one of them was using python for class projects.
gucci-on-fleek 2 hours ago [-]
> I think you might be able to go an additional decade backwards
Yeah, Python has had good Windows support at least 15 [0] or 25 years [1], depending on how you count it.
> Back in college most of my friends were on windows and one of them was using python for class projects.
Well it's always been possible to install Ruby on Windows too, it's just that Python supports it so much better.
Python's strength is that it's easy to make C libs work in it. That's also why CPython is de facto the only Python implementation and stuff like PyPy never took off.
hetman 47 minutes ago [-]
I like Python but this was always actually one of my pain points. The CPython C API is full of foot guns, the API surface is expansive, and writing against it requires a lot of careful care. Anyone who's ever written C modules for both languages would be able to attest how much more pleasant the experience was for Ruby than Python.
kccqzy 6 hours ago [-]
Yeah and I would say that another important factor is Cython, which compiles Python with minimal modifications to C extensions that can in turn be imported in Python. It really makes it easy to get started in Python and worry about performance of the computation later. (Doesn’t help with concurrency I know but that’s a different story.)
AdieuToLogic 6 hours ago [-]
> Python's strength is that it's easy to make C libs work in it.
SWIG[0] makes working with C libraries trivial for over a dozen programming languages; Perl, Python, and Ruby included.
There are reasons all those Py libraries with C code didn't just do it in SWIG.
AdieuToLogic 3 hours ago [-]
> There are reasons all those Py libraries with C code didn't just do it in SWIG.
And those reasons are?
dismalaf 6 hours ago [-]
Ruby can interface with C (or Odin, or anything that can export C style functions) just as easily.
hetman 47 minutes ago [-]
I would argue more easily.
Daishiman 4 hours ago [-]
How is a language that has different semantics for referring to lambdas vs other functions consistent?
Ruby's most important error is that it does not support namespaces. This by itself makes it a far less scalable language than Python.
hetman 57 minutes ago [-]
Did you mean to say that Ruby doesn't link name spaces to file system paths? Ruby has namespaces and they're far more flexible than Python's... too flexible in my opinion, making it harder to find things.
UqWBcuFx6NV4r 6 hours ago [-]
You don’t like working with data scientists. The data science Python ecosystem is really a separate beast that’ll have “normal” coders scratching their heads at the best of times, some of the most popular packages do all sorts of metaprogramming, and the standards for code quality are very different. Don’t blame the language. Well, blame it only in that it allows such things in the first place, which does have some very nice precipitations now and again, as well as some very bad ones.
In an age where people are still standing by C over memory-safe systems programming languages, I feel quite comfortable depending Python for the great many things that Python is good at.
fultonn 6 hours ago [-]
The performance hell thing is also also kind of a virtue, though. The language is awful, so everything that does any amount of compute is FFI'd into third party libraries (numpy, torch, sympy, etc). Those libraries are for the most part pretty well designed... or, at least, keep you in a few pretty well-constrained patterns that are easy enough to translate.
If you've ever read through FORTRAN code from a mathematics department or MATLAB/C/C++ from (non-software) engineering disciplines, then you probably understand why productionizing a jupyter notebook is definitely not the worst of all possible worlds.
ahartmetz 6 hours ago [-]
Python is a language for "consenting adults". It doesn't try to prevent you from doing awful things so you can do great things. People who can't program well are given plenty of rope to hang themselves. It shares that with Perl and Ruby.
That said, I find it the nicest, cleanest option of the three. I still wouldn't use it for large and complex projects. I really like it for stuff where one might otherwise use shellscript. It's way way better than shellscript... except if it's all about files and running external commands.
Revanche1367 5 hours ago [-]
>language for "consenting adults". It doesn't try to prevent you from doing awful things so you can do great things. People who can't program well are given plenty of rope to hang themselves.
This is exactly what I remember being said about C (which I agree with) and often given as a reason why higher level languages like Python or Java have so many protections against things C/C++ allowed (memory management being the biggest one of course). Very funny, and I assume not coincidental, to read this about Python in the modern programming landscape.
ahartmetz 4 hours ago [-]
Well, there are plenty of safety mechanisms that Python doesn't have and dangerous (usually powerful, occasionally badly designed) mechanisms that it does have.
jonhohle 6 hours ago [-]
Until someone adds a dependency…
ahartmetz 5 hours ago [-]
I generally just "apt install" them. pyenv and pip (just pyenv really) are a little clunky, but work too.
ks2048 7 hours ago [-]
> it’s slow
For little utilities, it’s faster than a lot of alternatives - just start the interpreter, no compilation needed.
It’s all relative, but if you view it as replacing bash scripts for renaming files or running other tools, it’s 100x better.
itissid 6 hours ago [-]
When one writes jupyter notebooks for DS you are not writing python. If you ask 10 DSs explain to me what python's attribute lookup model is and why is it different from other OO languages like say Java or C++, they would not care about it. The only thing DSs care about is the rich DS Library support and fast speed of protoyping. To a DS using jupyter this is almost the same feedback loop as a type system at compile time.
Have you tried using `uv`'s newer tools? They help a lot e.g. with linting speed, lock management, package dependency separation, correct python version mgmt and no need to fudge with venv.
renegade-otter 6 hours ago [-]
How is that a language problem? Data scientists are not engineers. No matter what language you give them, they will hand you something you are going to have to polish for production.
The fact that Python has become the language of choice for machine learning and data science is not a language issue.
qurren 6 hours ago [-]
I'm fine with the language. I just hate that you can't do
import numpy==1.5.4
and the code gets exactly the version it wants.
pjjpo 6 hours ago [-]
Relatively new, scripts can define dependency metadata now adays to achieve that to some degree. Any pip style versioning including an exact match works there.
The imports/packages situation is terrible in general. This was basically broken until uv, and uv is still not the default.
And it's weird how you import files. They're dot-separated packages that resemble file structure but not exactly. NodeJS has a self-explanatory require("./foo.js") or "../foo.js". The newer JS `import` syntax is annoyingly different from `require` but not terrible.
edparcell 6 hours ago [-]
I used to build quant investment notebooks that had to be deployed in production. Lots of problems with that. Mine were: Notebook cells run out of order, so you often have something that works in a session, but not in a fresh run. Developing against limited datasets, so you fail against things you didn’t know to test for. Small adaptions that have to be made every time the notebook is translated into a code file.
We streamlined it by making a graph-structured Computation a first class object that tracked staleness as code or data was updated. Then that class could be directly published, and when failures happened in production, the graph could be serialized with the inputs and intermediate calculation data that caused failure, for investigation in a notebook.
I've never become a fan of the language syntax, but otherwise I've become quite smitten with the total Python ecosystem. The Agents/LLMs + uv combo have made Python so useful and productive for me.
My CLI tools publish from Github to PyPI so that I can run tools with just `uvx sql-agent-cli` or `uvx dlna-here. Nothing for me to handle downloading (directly myself), no environment to manually setup, portable (Linux, Windows, Mac, ARM, x86). Easy for agents to run from a skill.md file without any other prereq than uv.
Really useful library ecosystem to leverage. No more shell scripts, or TS/JS/PHP backend services. I've even used Python on devices I've built around Raspberry Pi Zero 2 boards.
braiamp 6 hours ago [-]
> No more shell scripts, or TS/JS/PHP backend services
> I often work with data scientists and have to productionize their jupyter notebooks
At least it’s Python/Jupyter and not R, SAS, or MATLAB.
mjr00 7 hours ago [-]
> Python is awful.
> I often work with data scientists and have to productionize their jupyter notebooks
I'm not a huge Python fan, despite working with it fulltime, but this feels like mixing correlation and causation. Data scientists would not be writing good, optimized code in any language.
slashdave 7 hours ago [-]
Well, yeah. You might need to bring an R notebook into production.
itishappy 6 hours ago [-]
Scripting languages are awful. Python is one of the nicest scripting languages.
UqWBcuFx6NV4r 6 hours ago [-]
Holy 2000s! Are we really still doing “programming” vs “scripting”?
bigstrat2003 6 hours ago [-]
Why wouldn't we? It's still a very relevant distinction, even if the terminology is a bit weird (since scripting is by definition programming). A programmer has very different needs when he writes a script to automate some server tasks versus a complex piece of software. It makes perfect sense that different tools will be more or less effective at meeting those different needs.
Revanche1367 5 hours ago [-]
There is no reason why automating a server task cannot be a complex piece of software. I think you’re not aware of just what server automation is used for nowadays in countless cases. Also, Python is more popularly used in ML and web-development areas compared to server automation, so that would mean it’s not a scripting language by your logic.
Daishiman 4 hours ago [-]
Spoken like someone who hasn't tried to get data scientists to use other languages productively, where they'll be missing half the libraries, will have to triple their dependency count because you can't count on large common libraries and will have to dig to the ends of GitHub to find random functionality etc.
applfanboysbgon 7 hours ago [-]
Python is amazing compared to writing bat/sh scripts. Different languages are for different purposes, using eg. Rust to write system scripts would just be mental. Whether people abuse those languages for purposes they were not intended for is another story, but that doesn't mean the language is inherently bad. And I mean,
> and it’s way too easy to do the wrong thing
is there another programming language where you believe a data scientist is going to have an easier time writing correct code than Python? Do you think C or Rust or JavaScript or C# make it harder to do the wrong thing?
superze 6 hours ago [-]
C'mon man, I don't know any mid and above python developer who seriously has ever considered programming in Jupiter Notebooks. Python is not slow, it's you being the issue. If you are an amateur then it's easy to do the wrong thing, that's true.
nextaccountic 7 hours ago [-]
Seems like an excellent user for LLMs
xg15 9 hours ago [-]
Isn't "..." then also behaving like True, False and None, i.e. being a lexical token that rewolves to a hardwired value during parsing?
chrisweekly 7 hours ago [-]
rewolves?
EDIT: ah, "resolves" typo. was v curious about python's mysterious "wolfing" aspects
xg15 6 hours ago [-]
Yes, sorry, I had typed that on my phone. But yeah, now I want to know more too about python's new type wolfing paradigm.
zahlman 8 hours ago [-]
It is, but Ellipsis is just an ordinary pre-defined constant (with the same value).
xg15 6 hours ago [-]
Yeah, that makes sense.
b3orn 5 hours ago [-]
You wouldn't expect ... = 42 to work syntactically.
gucci-on-fleek 5 hours ago [-]
If you count pre-release versions, there are actually 7 pre-declared constants, since Python 3.15 (planned for release in November [0]) adds a new constant "TYPE_CHECKING" that should behave like "Ellipsis" and "NotImplemented" do right now [1].
Python is just such a weird language in general despite its popularity that I honestly cannot recommend anyone who starts programming to choose Python as their first language, contrary to popular sentiments. I mean, I was one of the first person to start using Python when I was in grad school almost a decade ago when everybody else in my field was still using Matlab for their lab code, for the simply reason that Numpy was less awful than Matlab and I needed something that can easily print graphs to PDFs.
The only thing good I can say about Python nowadays is that it's easy to get started for the first five minutes, and then you'll have to deal with all of its weirdness: significant whitespace, truthiness, duck typing, GIL, distribution/packaging, etc, etc.
I was a big fan of Julia as the potential replacement for Python for science for such a long time and I had evangelized it a lot previously, but recently I've been more and more convinced that JIT/multiple dispatch was only good if you already know how to program well to begin with, which for a lot of academics who are not working in computer science, they write quite horrific code. I think it may be better off to skip Python altogether and write your code in a statically typed language to begin with.
Waterluvian 5 hours ago [-]
I think Python remains a very good intro language for getting kids in the door because it doesn’t demand too much tedious stuff, is flexible, and lets people actually solve problems rather than doing computer science.
In my experience the difficulty is understanding what exactly is important when teaching someone something new. And it largely depends on the goals. What you’d teach some biology undergrad is going to be very different from what you teach a bunch of robotics team high schoolers (and no you’re not teaching them the best language for controls and embedded).
rmunn 5 hours ago [-]
What is the best language for controls and embedded, in your opinion? I assume from your comment that it's not a great choice as a first language to teach newbies, but I've never done anything in the field of robotics or embedded stuff, so I'm quite ignorant in that area.
YuechenLi 5 hours ago [-]
If I'm not allowed to toot my own horn, I think for controls, you probably should not start with choosing a programming language, the first step is learning control theory and automata theory, you kinda have to understand feedback control/PID/steady state/jitter/hysteresis and the like. Python has never had great control libraries to begin with as far as I can remember (my info could be a bit outdated though), so the paid option is still Matlab/Simulink as it is their last niche really.
Embedded firmware, probably C/C++/Rust. Not the answer you want to hear, but these are the languages for bare metal applications. Of course, if you are just using an Arduino/Pi, just use their SDK for their hardware on whichever language they support.
Those two fields are just not very friendly towards beginners in general.
Sure, short list:
- Easier to write than Python other than the simplest script, almost no way to write bad code and have it compile, reads like pseudocode most of the time
- Compiles into Go binary, runs at Go speed, compiles at Go speed
- Trivial to wrap any Go library via LLMs, so any Go library is also an Oct library.
- Can metaprogram existing Go codebases, so it doesn't really replace Go, just supplements it
- Easy concurrency/parallelism
- SI units as types
- Can be used as build script for C/C++ in place of CMake
- Einstein tensor notation
- Builtin GPU acceleration via Vulkan
It was designed as a teaching language for academics to stop writing bad code, but now I just get LLMs to do research/science for me with it for fun.
Waterluvian 5 hours ago [-]
Yeah! Like when helping teens set up PID controllers for their CAN-bussed robot, it was very much a "we've got a lot of example working Java code with a PID Controller library already. So we're using that." The language itself is so inconsequential at the early stage, that you really just pick whatever gets in your way the least.
Waterluvian 5 hours ago [-]
None of them. Walks away. Stops. Turns. All of them.
It depends. If you're a teen I'm mentoring, you're probably starting with some Scratch to drive Lego robots around. Then on to Python to drive the same robots around but now with more fun!. Probably because you absolutely couldn't stand the standard line follower solution of jittering back and forth and you sniffed out the existence of better control loops you cannot realize in Scratch. If you're on the FIRST Robotics team you're probably doing Java or Python, mainly because that's just what we've geared up for (and this is really the core theme for me at least: at introductory levels, what really matters most is whatever is most readily accessible to you and whatever kit you already have).
If you're doing your own stuff and you're a newbie with absolutely no opinions on where you started or what you were trying to do, you'd probably start poking around with an Arduino or similar, so you could write MicroPython (it's Python but you squint your eyes a bit!) or C. There's so many great kits for beginners.
In the context of my comment: what I meant is that you wouldn't decide, "the professionals do it in C++, C, or Rust, so we'll start with one of those." I'm going to give you a recorder (Python) before I hand you bagpipes (C++).
rmunn 4 hours ago [-]
If I'm teaching you programming and you've learned Scratch, I'm going to hand you Snap! (https://snap.berkeley.edu/) next. Because it's Scratch, but with the artificial limiters removed. Snap! (the exclamation mark is part of the name) allows you to store lists in variables and pass them as inputs to functions, and it has the standard list-handling functions you'd expect, like filter and map. Moreover, it also allows you to store blocks (functions, basically) in data structures and pass them as inputs to other blocks, so you can actually learn to write code in functional-programming style.
Once you learn that Brian Harvey, one of the two main designers of Snap!, was one of the principle people behind Berkeley Logo (which itself was a variant of Lisp, though that wasn't clear to me when I was learning Logo at age eight), it all starts to become clear. Snap! is itself nearly a Lisp, just lacking macros (and Brian Harvey is trying to figure out how to add a macro system to Snap!, with the primary challenge being making it comprehensible in graphical-blocks form).
Waterluvian 4 hours ago [-]
We’re spoiled with great options. My kid jumped right from Scratch to JavaScript for game dev because he loves how he can put his games on the Web easily. Huge props to Microsoft Make Code Arcade for allowing you to port your Scratch to JS. It gave him a powerful way to see what he knows and how it looks like in JS.
belorn 5 hours ago [-]
Are academics who are not working in computer science interested in learning statically typed programming languages?
In the past, the usual answer to people who need a programming language but did not want to learn programming was to give them a domain specific language that focused on solving the specific problem they wanted to solve.
YuechenLi 5 hours ago [-]
Well, many times in my field of mechanical engineering, they have to, because CFD and FEA are very performance sensitive. The professors I had were still writing FORTRAN and C++ before, but maybe they've switched to Rust now.
gucci-on-fleek 5 hours ago [-]
> I honestly cannot recommend anyone who starts programming to choose Python as their first language, contrary to popular sentiments
> I think it may be better off to skip Python altogether and write your code in a statically typed language to begin with
Having a good REPL is a huge advantage for beginners (and expert users too), but I'm not aware of any (popular) statically-typed languages with a good REPL.
Despite Python's many faults, it's easy to install (especially on Windows), it has a large standard library, there are third-party packages available for essentially everything, it comes with a user-friendly REPL out-of-the-box, and it gives comprehensible error messages. I'm not really aware of any other (popular) languages with all these attributes.
fultonn 5 hours ago [-]
> Having a good REPL is a huge advantage for beginners (and expert users too), but I'm not aware of any (popular) statically-typed languages with a good REPL.
scala's repl is decent. It has its annoyances, but so does python's (white space sensitivity + repl + terminal emulators stuck in the late mid century don't mix).
Chinjut 5 hours ago [-]
I hate Python and I'm onboard with putting it down in many ways, but significant whitespace isn't weird in a first programming language. It's only weird if you've absorbed from some other language the convention that whitespace shouldn't be significant.
YuechenLi 4 hours ago [-]
Oh, by "significant whitespace" I meant whitespace sensitive indentation, which I think Python and YAML are the only languages that has that feature.
Chinjut 4 hours ago [-]
Haskell, Lean, and Agda too. But even if Python were the only one, it wouldn't be weird to someone for whom this was their first programming language. It would just seem the way programming languages are. There's nothing intrinsically weird about indentation being significant. It's quite visibly part of the code you write and read.
toast0 4 hours ago [-]
> There's nothing intrinsically weird about indentation being significant. It's quite visibly part of the code you write and read.
The idea is fine, I guess, although I certainly don't care for it. Where it gets most nasty is that whitespace that looks the same (in your editor) might not be equal and will cause you pain.
YuechenLi 4 hours ago [-]
Hmm. Learned something new today. Thanks.
rmunn 4 hours ago [-]
F# as well.
persedes 6 hours ago [-]
Love the investigation and write up.
Took me down some rabbit holes, but interesting to see the chatter about the fix here:
> True, False, and None are keywords. they aren't identifiers, they're just straight up their own lexical tokens.
Could this be so that the interpreter don't inadvertently manipulate them or pass them to a function? param=None and param="" can be very different.
rmunn 5 hours ago [-]
It also helps prevent people from ever redefining them. I mean, if you try to redefine False (in a version of Python that allows it) then you deserve everything that's about to happen to your code... but at the same time, it could possibly lead to a security attack. Redefine False then import some module and get unexpected behavior that you can manipulate to your advantage, somehow. I don't know how that would work, it probably wouldn't... but there's also no reason not to lock those names in and prevent them from ever being redefined.
snitty 7 hours ago [-]
Python is three scripting languages in a trench-coat.
Lucasoato 7 hours ago [-]
Wow, I wish to understand the internal details of Python implementation that makes it behave in such a way :)
wildzzz 6 hours ago [-]
I don't. I have no interest in trying to assign a value to something that's built-in and not meant to be written to. Like who fucking cares that the boolean constants are actually weird little structure that sometimes let you mess with them and other times your edits are ignored? Maybe this is helpful for writing an entry for an obfuscated code challenge but I'm not doing weird shit like that with the code I expect to work between various Python versions and implementations, especially when I'm getting paid to do it.
UqWBcuFx6NV4r 6 hours ago [-]
Please. Such a charged response wasn’t justified at all. Different people are curious about different things. You ask “who fucking cares?”. The answer? You don’t, and the person you’re replying to does.
jMyles 8 hours ago [-]
I made a constant library for python which I liked some years ago. I wonder if any of my ideas made it in:
Yeah it was a blast to make. If memory serves, a significant piece was over a very lovely and piney joint with Kieran Prasch at an airbnb in... Seattle?
throwaway314155 5 hours ago [-]
Queue the hoards of Python haters apparently.
echelon 8 hours ago [-]
I used to like Python in the 2010s when it felt like a breath of fresh air relative to PHP and Perl.
Now it feels like a weird PHP itself that is slow, brittle, and dangerous to write code at scale in.
The loose typing, potluck standard library, and horrible package manager (insofar as the community does not know how to package code) all feel so dated.
plant-ian 8 hours ago [-]
I felt the same way about moving to Python versus PHP and Perl.
I still really enjoy using python though. It's not really a fair comparison because I hadn't used PHP and Perl for as long but I just don't hit some mystifying issue every single session like I did with those languages when I'm using python. I honestly have never even read about that __debug__ constant. It's fun to hear about it but it's just not something that's comes up much.
wredcoll 7 hours ago [-]
Perl is a lot like that also, you can read about some really weird old features like $[ but you never see that in practice, you just write code with variables and functions and so on.
datakan 8 hours ago [-]
It is 30+ years old with all the baggage you would expect. It’s very much a product of its time.
9dev 8 hours ago [-]
It’s not like that cannot be changed. Look at PHP, which managed to evolve brilliantly over the last decade and gets tons of things right now.
snitty 7 hours ago [-]
I keep on hearing people be excited about PHP. Having first attempted to use PHP in early 00s, I simply cannot bring myself to attempt it again. I once had to rewrite large chunks of a site because it simply couldn't deal with the fact that a string had an apostrophe in it.
9dev 37 minutes ago [-]
I can only recommend to check out a popular project, maybe Laravel, and read it’s documentation. Alternatively, look at the PHP website itself. The new syntax improvements alone are pretty convincing IMHO, but the engine also got a JIT compiler, a runtime type system that’s fully opt-in, fibers for concurrency, and much more.
It’s really worth a second look.
thayne 7 hours ago [-]
PHP has evolved a lot, but it also still has a lot of cruft from its earlier days. And it has made breaking changes on a scale python probably couldn't get away with.
9dev 36 minutes ago [-]
Show me a language that old without lots of cruft. The worst thing you can find is the standard library, which is just an unsolvable problem.
randallsquared 8 hours ago [-]
Python 3(000) was an opportunity to fix all the things, so in a sense, the modern Python is less than 20 years old.
KK7NIL 8 hours ago [-]
Python certainly has some baggage, especially the typing system (which is still not finished, if you're looking at static typing and so is implemented differently by type checkers) and pip's safety, or lack thereof. But comparing it to PHP or Perl is rhetoric leading you one step too far.
fugigigjfn 8 hours ago [-]
Comparing it with PHP is unfair… to PHP. The amount of hard work that the PHP community has done to advance and keep their language relevant is impressive and admirable, and Python is perhaps the most extreme counterexample there is.
The Python community has spent the last 15 years refusing to improve in any meaningful way, or to learn anything from their peers. As someone who used to choose only jobs that would let me work with Python, I’ve gone through every phase of grief, and now just try to forget that it exists.
mixmastamyk 7 hours ago [-]
Lol, Python has had incredible improvements over the last decade plus, while uv fixed packaging. It's the best/comprehensive glue language ever made, even with a few remaining warts.
rmunn 7 hours ago [-]
Most of the time downvoters don't explain their downvote, but I'll explain mine. I voted this comment down because it's just plain incorrect.I worked with PHP for nearly ten years (and I never want to go back). Maybe PHP has improved since I worked with it (PHP 7.4 was the most recent version when I last worked with it, I have never used PHP 8), but I doubt it.
But to describe the Python community as "spen[ding] the last 15 years refusing to improve in any meaningful way" is just laughably wrong. I can't give details as I haven't been doing much Python work, but even so I know of multiple changes, such as the typing system, or packaging improvements, which have significantly improved the language AFAICT. If there's a reason why you would not consider those to be "improv[ing] in any meaningful way", please enlighten me.
mixmastamyk 5 hours ago [-]
You mentioned two biggies, but also the GIL removal, async, performance improvements, f-string, walrus, fast dicts w. merge ops, data classes, pattern matching, friendlier repl, and hundreds of smaller yearly improvements.
rmunn 4 hours ago [-]
Pattern matching? Nice, I'd managed to miss that one completely, as well as the fact that Python had introduced dictionary-merging (according to a quick search, Python 3.9 introduced the | (pipe) operator for dict unions). I did know about the others you mentioned, but couldn't call them to mind when writing my comment.
But reading through a Python script that I had Claude Code write for me taught me another one: apparently there's now a / operator on strings, because Claude wrote `path = "some" / "dir" / "filename.txt"` without importing anything outside of the stdlib. I presume it is shorthand for calling os.path.join and will therefore apply the correct path separator on Linux vs Windows.
mixmastamyk 3 hours ago [-]
Yes, that's a Path object from pathlib. It has been around for while but likely still qualifies, site says from 3.4.
adamddev1 8 hours ago [-]
I don't understand how people talk about how Python is "easy to learn for beginners" or "easy to understand." To me it's so hard to remember and follow all the weirdness. Racket / Scheme / I dare say even Haskell would just be so much simpler for learners.
I'm with Conal Elliot when he said on Type Theory for All that it is sooo much harder to understand a program in Python.
kalenx 7 hours ago [-]
I can understand that "advanced" python programs may be difficult to understand for beginners (lots of implicit/hidden behaviors, possibility to change basically everything one should expect, etc).
But to _learn_ programming, I really, really don't see how using Haskell would be simpler than Python. Perhaps if you have a specific background (e.g., math), but else python is almost pseudo code already. You'll really have to convince me that a more abstract language is better...
fn-mote 6 hours ago [-]
Haskell’s hard to interpret error messages alone disqualify it from being a beginner language.
Python: errors based on incorrect indentation (many beginners don’t use nice IDEs), or don’t understand the meaning of the hints) and scope (don’t forget your “global” if you’re hacking in PyGame) are challenges.
6 hours ago [-]
wredcoll 7 hours ago [-]
It would help a lot if every single racket/scheme example wasn't entirely made of single character variables.
quadrifoliate 7 hours ago [-]
> Racket / Scheme / I dare say even Haskell would just be so much simpler for learners.
I have used all three languages; and you clearly have no idea of the notion of usability of a language. So many things contradict this, let me list them off the top of my head
- Getting a running toolchain working: Prexisting (most OSes bundle a Python interpreter) or a package install away for Python. Scheme / Racket is some odd mix of custom IDEs with Dr. in the name, or someone's 20 page essay on how SLIME is the best thing ever. Haskell gets into odd stuff with ghci, cabal, and stack, and all of them are extremely slow.
- Tutorials: Python has a ton of them, they all get you printing to stdout and calculating things in about 10 minutes. Scheme / Racket typically spends multiple chapters navel-gazing about lists, cons, and such. Haskell is actually better in terms of the Hello World stuff, but ghci v/s ghc bites you again; and no one has a clear idea of which one to use.
- Advanced concepts: Python has mainstream but halfhearted OOP; and things like decorators and metaprogramming. Quickly intelligible if you learned something else like Java or C++. Or if you learned shell scripts you can get quite a bit done with just imperative. Racket/Scheme: 3 chapters in and you're still trying to figure out tail recursion. Haskell: Instead of just doing fun things with take and foldl you're being hit with trivia about typeclasses.
fn-mote 6 hours ago [-]
> Quickly intelligible if you learned something else like Java or C++
You’re replying to a post making assertions about beginners.
That doesn’t usually mean people with 4 years programming experience picking up a new language.
Racket: criticizing for having a beginner-friendly IDE doesn’t make a lot of sense. There’s always Magic Racket for VSCode for the others.
I guess you’re not starting people with “How to Design Programs” because that’s pictures and animations for ages.
Haskell: that was funny but an absurd criticism ghc vs ghci?? Nobody has that problem. The other stuff - valid but lead with it instead of trolling.
quadrifoliate 5 hours ago [-]
> Haskell: that was funny but an absurd criticism ghc vs ghci?? Nobody has that problem.
Back when I was a beginner actually interested in getting out of the beginner step of Haskell, this was an issue for me times. So there's at least one person :)
Also anecdotally I have seen people ask this in Freenode #haskell as well (the “Freenode” probably tells you how long ago this was) ; and there a few issues [1] and [2] where I see beginners having the same/similar issue. The second one is particularly funny, 4 people give 5 solutions and no one seems to know what the actual fix is. Instead you have people arguing whether a repeated do works or not. This would never happen with Python, just saying :)
> Racket: criticizing for having a beginner-friendly IDE doesn’t make a lot of sense.
Sorry, perhaps too harsh but I don't think it's as beginner-friendly as you think. I think it would probably help if they made the design more modern and welcoming. All these details about you can rewrite entire languages in Lisp and we can't even at least get a GUI that looks like it was written after 2007?
I feel the same way. It was, back then “the second best language for everything, the first best at nothing”
Can’t take credit for the quote, read it somewhere.
The whole language changed when they kicked what’s-his-name out, and it’s a tool I almost never reach for anymore, whereas 15 years ago it was my Swiss Army knife.
slopinthebag 8 hours ago [-]
Who cares tho. The agents deal with all of that, if you’re still looking at the code or caring about anything other than the loops and orbs you’re at the wrong level of abstraction. The important thing is the models have tons of python in their training data.
SCUSKU 8 hours ago [-]
I've heard of orbs but what is it actually?
slopinthebag 4 hours ago [-]
It’s basically self-contained cloud agents. I’m not sure why they’re called that but I think it’s just the next grift, kinda like “loops”…
luciana1u 5 hours ago [-]
you could shadow True for twenty years and Python just shrugged, then one day it's a SyntaxError and every tutorial you ever wrote breaks. peak Python, honestly.
denislexic 6 hours ago [-]
[dead]
moomoo11 7 hours ago [-]
just my 2c but py is honestly one of the worst languages and ecosystems i’ve used in my life.
for all the hate js used to get, py is at least a few magnitudes worse.
my opinion ofc. don’t get mad xD
Vedor 7 hours ago [-]
I'm not mad, but curious - I use Python for years and only dabbled with JS. Could you elaborate what makes Python magnitide worse than JavaScript?
Chu4eeno 7 hours ago [-]
Don't mind the web designers calling themselves engineers.
There's a lot of annoying issues with Python, but compared to the billions of dollars and thousands of man hours that has been spent trying to fix Javascript and how horrible it still is, it's a perfectly cromulent language.
wredcoll 7 hours ago [-]
There are two kinds of languages, ones that people complain about and ones nobody uses.
https://www.oreilly.com/library/view/javascript-the-good/978...
Helped me get a more pragmatic approach to use that chaotic mess of a language and environment. Just use what works, ignore the rest (but I also ignored some specific advice from the book and used what worked for me).
Every single new, large feature in JS has been full of quirks. The same cannot be said for Python; the exceptions are few and far between and more often than not they're not actually exceptions but rather something bound to core language fundamentals which once understood don't present a challenge because there is an actual underlying consistency.
In about the same timeline, Py went from threading to async-await, which created classic blocking vs nonblocking mismatches. The whole 2 to 3 breaking migration was also still a big deal in 2015.
(Note some of these are outdated, but some of those only mention that towards the end of the section rather than the beginning)
I challenge you to find Python behaviors as weird and off-putting as anything here: https://wtfjs.com/
Python has weird file imports (no relative ones either), broken package management, historical differences between asyncio and blocking that still cause issues, threading/GIL caveats that trip up even experienced users, indentation for scope (esp weird given it was designed for REPL), weirdly no anonymous functions, 2 vs 3 (mostly gone by now), the __init__ and __init__.py stuff, namedtuple vs dict vs object, `global`, and a whole mess with type-linting if you're going there. You have to deal with all those things every time.
Here's one little Python footgun that everyone hits and is also annoying after:
For example, why would you expect `Boolean("false")` to equal `false`? It's a string, and bears no relation to the Boolean type. [0]
[0] https://wtfjs.com/wtfs/2014-10-07-true-equals-false
They each have different quirks (some will parse 'a123' as 123, others will handle scientific notation etc). The only reliable way of doing this is doing a regex followed by parseInt... which is definitely a footgun IMO.
What makes this weirder than other languages detecting if they’re an import or an invoked file?
__this_file__ == “__launch_file__”
or similar. I understand python values “only one way” of doing things, but it would be helpful for readability.
Nice to see it get attention this time.
Sure, it's not a language to write a web browser or game engine in. And it is slow. But it has some very strong niches outside of ML/Data science. Personally, I love it. To each their own.
uv + PEP723 make this even better.
I’ve of course certainly heard of, seen, and used `assert`, but more often than not, outside of pytest, I see its use way more in potential footgun scenarios—I doubt that many people know that assertions can be silenced, and that they’d probably be better off raising exceptions in many cases where they’re using `assert`.
I would not be surprised in the least if that pattern existed in the wild. In fact, it's quite common to see this in C/C++ codebases too: people will use assert() to check a security-relevant property, and then disable those checks in their release builds "because it can't happen".
Assigning to __debug__ wouldn't do anything to the compiler as it never actually reads the variable, so assignment would just cause weirdness from other use
True = 1
False = 0
then later these got added to the language. In Python 2 you could still reassign and swap them so that 'if False' was actually true!
True, False = False, True
Python 3 you could no longer reassign them.
Common language design boners:
- Not building in strings. That's now in the past. Everybody has strings. (Well, C...)
- Not building in multidimensional arrays of the numeric types. Everything that number-crunches needs them, and having multiple definitions is Not Fun and may lead to expensive re-copying between different libraries. This is an enormous blind spot in language design. It's one of the reasons FORTRAN, which has good multidimensional numeric arrays, is still often used for number-crunching.
- Not standardizing the small vectors (vec2, vec3, vec4) and their matrix friends. Graphics code depends on these, and it's really annoying if there are multiple slightly incompatible implementations. Especially since GPUs have hardware for those types, and you want CPU and GPU to use the same representations.
- Not having arrays of bits. Pascal had PACKED ARRAY[0..N] of BOOLEAN but that was lost in later languages. It's useful to have that as a language construct, because most modern CPUs have good hardware for dealing with bit strings, and you'd like the compiler to use it.
Most useful languages acquire these features, but, when they come in late, there are multiple similar implementations, and libraries made incompatible by depending on different implementations.
(Amusingly, when Second Life switched from Linden Scripting Language to Luau, they initially had True, TRUE, and true all in use, as different types with different semantics. I was able to persuade the devs to unify the boolean types.)
Several times now†, people make a language where the way a for-each loop (for each Goose in Geese ...) works is that there's a single variable Goose and each time around the loop we change which value is referred to by the Goose variable. This seems intuitively like a reasonable way to do this. But it's wrong and eventually your programmers will get nasty surprises. What you actually should deliver is an implementation where each time around the loop there's a new variable named Goose, that variable goes away at the end of that iteration and will be replaced by the next one, with the same exact name.
† At least Go and C#, I think there are others
Is this because a closure inside a loop will capture a reference to `Goose`?
I think that this is a capture problem not a variable problem. The closure should always do the right thing and capture the value of all variables (not just ones inside the loop), instead of capturing the reference to the variables.
Then the general problem is fixed to match what developers expect, instead of a specific instance of that class of problems being fixed and working differently to how other captured variables work.
I'm not sure exactly which features are responsible (I'm inclined to blame templates), but C++'s std::vector<bool> is a rough edge. For those unfamiliar, the standard specifies this vector template in a way that's not compatible with other vectors.
I'd consider LSL to have been foundational in my ultimate interest/career in software engineering. The strict typing, very usable compile/runtime errors, and good documentation/examples made it so easy to pick up as a teen. Not to mention as long as you didn't edit/save a script again it would always run the same regardless of updates.
It kind of started with vectors as the very first feature (I was sick & tired of libraries reinventing their own `Point`/`VectorN` in incompatible ways).
Definitely agree on multidimensional arrays. I feel like efficient arrays in general are underrated in high-level language design.
The thing you want is what Rust delivers in the box, &str a string slice reference type, in Rust's case the "string" is UTF-8 encoded text. On the bare metal the way to represent this type is as a "fat pointer" typically a pair of registers, one with the address of the first byte of the string and the other with a length.
C should have fat pointers, they were proposed, for IIRC C89 but the proposal was rejected. That's pretty sad, the fat pointer is expensive to the point of maybe feeling extravagant on a PDP-11, but by 1989 that's long gone.
More ridiculously C++ didn't get this type (which it eventually called std::string_view and provides in its standard library not as a built-in) until 2017, years after Rust 1.0 shipped. In the meanwhile C++ just did not have a sensible way to do this, strings are hard apparently.
The string buffer feature, allowing you to actually make strings is less important, as you say it will need an allocator and so on very bare metal you might not have this - but the string slice reference doesn't need an allocator.
I think it's worth delivering the basic "it's a growable array type, duh" implemenation of the string buffer type, which is what Rust's String type is, but C++ chooses to ship an oddly specific small-string optimized version as std::string right from the offset.
Ruby has such a nice holistic consistency to it. With a few exceptions, it feels like it was conceived of by one person with a core idea in mind. Python feels like a mess.
Likewise, it made classes incredibly easy to extend, which led to a monkey patching bonanza and far too much magic everywhere (Rails being by far the worst offender but not the only one). It meant having to keep too much stuff in your head and needing deep framework/library familiarity just to be able to understand basic code.
In the end, I feel like the incredible flexibility was Ruby's undoing, not just lack of library availability for a specific popular application. I was a Ruby zealot at one point but it began to lose its lustre not because it wasn't beautiful in theory, but because it was inconvenient in practice. In some ways, Python's restrictiveness became its greatest attribute. Then Python 3 helped to fix a lot of the inconsistency.
Both Python and Ruby have a consistent logic to them, just not consistent with each other. Just as all attributes are methods in Ruby, so all methods area attributes in Python, etc. Things get much easier in either language if you stop fighting their internal logic.
This is just my personal opinion with no data to back it up, but I suspect that Python "won" because it has excellent Windows support, while Ruby doesn't. Even a decade ago, Python's website offered an official native Windows installer [0], while Ruby's website [1] still points you to a third-party installer, which doesn't even have native support since it uses MSYS2 [2].
Most non-developers use Windows, so if you're choosing the first language to teach a large group of people, good Windows support is fairly important. Python being the "default" introductory language gave it a huge number of users, then I suspect that everything flowed down from there.
[0]: https://web.archive.org/web/20160824235759/https://www.pytho...
[1]: https://www.ruby-lang.org/en/downloads/
[2]: https://rubyinstaller.org/
I think you might be able to go an additional decade backwards. Back in college most of my friends were on windows and one of them was using python for class projects.
Yeah, Python has had good Windows support at least 15 [0] or 25 years [1], depending on how you count it.
> Back in college most of my friends were on windows and one of them was using python for class projects.
Well it's always been possible to install Ruby on Windows too, it's just that Python supports it so much better.
[0]: https://peps.python.org/pep-0397/
[1]: https://peps.python.org/pep-0277/
SWIG[0] makes working with C libraries trivial for over a dozen programming languages; Perl, Python, and Ruby included.
0 - https://www.swig.org/
And those reasons are?
Ruby's most important error is that it does not support namespaces. This by itself makes it a far less scalable language than Python.
In an age where people are still standing by C over memory-safe systems programming languages, I feel quite comfortable depending Python for the great many things that Python is good at.
If you've ever read through FORTRAN code from a mathematics department or MATLAB/C/C++ from (non-software) engineering disciplines, then you probably understand why productionizing a jupyter notebook is definitely not the worst of all possible worlds.
That said, I find it the nicest, cleanest option of the three. I still wouldn't use it for large and complex projects. I really like it for stuff where one might otherwise use shellscript. It's way way better than shellscript... except if it's all about files and running external commands.
This is exactly what I remember being said about C (which I agree with) and often given as a reason why higher level languages like Python or Java have so many protections against things C/C++ allowed (memory management being the biggest one of course). Very funny, and I assume not coincidental, to read this about Python in the modern programming landscape.
For little utilities, it’s faster than a lot of alternatives - just start the interpreter, no compilation needed.
It’s all relative, but if you view it as replacing bash scripts for renaming files or running other tools, it’s 100x better.
Have you tried using `uv`'s newer tools? They help a lot e.g. with linting speed, lock management, package dependency separation, correct python version mgmt and no need to fudge with venv.
The fact that Python has become the language of choice for machine learning and data science is not a language issue.
https://packaging.python.org/en/latest/specifications/inline...
And it's weird how you import files. They're dot-separated packages that resemble file structure but not exactly. NodeJS has a self-explanatory require("./foo.js") or "../foo.js". The newer JS `import` syntax is annoyingly different from `require` but not terrible.
We open sourced the implementation https://github.com/janushendersonassetallocation/loman
My CLI tools publish from Github to PyPI so that I can run tools with just `uvx sql-agent-cli` or `uvx dlna-here. Nothing for me to handle downloading (directly myself), no environment to manually setup, portable (Linux, Windows, Mac, ARM, x86). Easy for agents to run from a skill.md file without any other prereq than uv.
Really useful library ecosystem to leverage. No more shell scripts, or TS/JS/PHP backend services. I've even used Python on devices I've built around Raspberry Pi Zero 2 boards.
You didn't use Perl before? https://xkcd.com/353/
At least it’s Python/Jupyter and not R, SAS, or MATLAB.
> I often work with data scientists and have to productionize their jupyter notebooks
I'm not a huge Python fan, despite working with it fulltime, but this feels like mixing correlation and causation. Data scientists would not be writing good, optimized code in any language.
> and it’s way too easy to do the wrong thing
is there another programming language where you believe a data scientist is going to have an easier time writing correct code than Python? Do you think C or Rust or JavaScript or C# make it harder to do the wrong thing?
[0]: https://peps.python.org/pep-0790/#schedule
[1]: https://peps.python.org/pep-0781/#backwards-compatibility
The only thing good I can say about Python nowadays is that it's easy to get started for the first five minutes, and then you'll have to deal with all of its weirdness: significant whitespace, truthiness, duck typing, GIL, distribution/packaging, etc, etc.
I was a big fan of Julia as the potential replacement for Python for science for such a long time and I had evangelized it a lot previously, but recently I've been more and more convinced that JIT/multiple dispatch was only good if you already know how to program well to begin with, which for a lot of academics who are not working in computer science, they write quite horrific code. I think it may be better off to skip Python altogether and write your code in a statically typed language to begin with.
In my experience the difficulty is understanding what exactly is important when teaching someone something new. And it largely depends on the goals. What you’d teach some biology undergrad is going to be very different from what you teach a bunch of robotics team high schoolers (and no you’re not teaching them the best language for controls and embedded).
Embedded firmware, probably C/C++/Rust. Not the answer you want to hear, but these are the languages for bare metal applications. Of course, if you are just using an Arduino/Pi, just use their SDK for their hardware on whichever language they support.
Those two fields are just not very friendly towards beginners in general.
It was designed as a teaching language for academics to stop writing bad code, but now I just get LLMs to do research/science for me with it for fun.
It depends. If you're a teen I'm mentoring, you're probably starting with some Scratch to drive Lego robots around. Then on to Python to drive the same robots around but now with more fun!. Probably because you absolutely couldn't stand the standard line follower solution of jittering back and forth and you sniffed out the existence of better control loops you cannot realize in Scratch. If you're on the FIRST Robotics team you're probably doing Java or Python, mainly because that's just what we've geared up for (and this is really the core theme for me at least: at introductory levels, what really matters most is whatever is most readily accessible to you and whatever kit you already have).
If you're doing your own stuff and you're a newbie with absolutely no opinions on where you started or what you were trying to do, you'd probably start poking around with an Arduino or similar, so you could write MicroPython (it's Python but you squint your eyes a bit!) or C. There's so many great kits for beginners.
In the context of my comment: what I meant is that you wouldn't decide, "the professionals do it in C++, C, or Rust, so we'll start with one of those." I'm going to give you a recorder (Python) before I hand you bagpipes (C++).
Once you learn that Brian Harvey, one of the two main designers of Snap!, was one of the principle people behind Berkeley Logo (which itself was a variant of Lisp, though that wasn't clear to me when I was learning Logo at age eight), it all starts to become clear. Snap! is itself nearly a Lisp, just lacking macros (and Brian Harvey is trying to figure out how to add a macro system to Snap!, with the primary challenge being making it comprehensible in graphical-blocks form).
In the past, the usual answer to people who need a programming language but did not want to learn programming was to give them a domain specific language that focused on solving the specific problem they wanted to solve.
> I think it may be better off to skip Python altogether and write your code in a statically typed language to begin with
Having a good REPL is a huge advantage for beginners (and expert users too), but I'm not aware of any (popular) statically-typed languages with a good REPL.
Despite Python's many faults, it's easy to install (especially on Windows), it has a large standard library, there are third-party packages available for essentially everything, it comes with a user-friendly REPL out-of-the-box, and it gives comprehensible error messages. I'm not really aware of any other (popular) languages with all these attributes.
scala's repl is decent. It has its annoyances, but so does python's (white space sensitivity + repl + terminal emulators stuck in the late mid century don't mix).
The idea is fine, I guess, although I certainly don't care for it. Where it gets most nasty is that whitespace that looks the same (in your editor) might not be equal and will cause you pain.
Took me down some rabbit holes, but interesting to see the chatter about the fix here:
https://github.com/python/cpython/issues/80233
Initially you could reassign True,False but that was verboten with the switch to python 3! The walrus operator was the one simply an oversight.
https://python-history.blogspot.com/2013/11/story-of-none-tr...
Explanation from Guido himself
Could this be so that the interpreter don't inadvertently manipulate them or pass them to a function? param=None and param="" can be very different.
https://github.com/nucypher/constantSorrow/blob/master/tests...
Now it feels like a weird PHP itself that is slow, brittle, and dangerous to write code at scale in.
The loose typing, potluck standard library, and horrible package manager (insofar as the community does not know how to package code) all feel so dated.
I still really enjoy using python though. It's not really a fair comparison because I hadn't used PHP and Perl for as long but I just don't hit some mystifying issue every single session like I did with those languages when I'm using python. I honestly have never even read about that __debug__ constant. It's fun to hear about it but it's just not something that's comes up much.
It’s really worth a second look.
The Python community has spent the last 15 years refusing to improve in any meaningful way, or to learn anything from their peers. As someone who used to choose only jobs that would let me work with Python, I’ve gone through every phase of grief, and now just try to forget that it exists.
But to describe the Python community as "spen[ding] the last 15 years refusing to improve in any meaningful way" is just laughably wrong. I can't give details as I haven't been doing much Python work, but even so I know of multiple changes, such as the typing system, or packaging improvements, which have significantly improved the language AFAICT. If there's a reason why you would not consider those to be "improv[ing] in any meaningful way", please enlighten me.
But reading through a Python script that I had Claude Code write for me taught me another one: apparently there's now a / operator on strings, because Claude wrote `path = "some" / "dir" / "filename.txt"` without importing anything outside of the stdlib. I presume it is shorthand for calling os.path.join and will therefore apply the correct path separator on Linux vs Windows.
I'm with Conal Elliot when he said on Type Theory for All that it is sooo much harder to understand a program in Python.
But to _learn_ programming, I really, really don't see how using Haskell would be simpler than Python. Perhaps if you have a specific background (e.g., math), but else python is almost pseudo code already. You'll really have to convince me that a more abstract language is better...
Python: errors based on incorrect indentation (many beginners don’t use nice IDEs), or don’t understand the meaning of the hints) and scope (don’t forget your “global” if you’re hacking in PyGame) are challenges.
I have used all three languages; and you clearly have no idea of the notion of usability of a language. So many things contradict this, let me list them off the top of my head
- Getting a running toolchain working: Prexisting (most OSes bundle a Python interpreter) or a package install away for Python. Scheme / Racket is some odd mix of custom IDEs with Dr. in the name, or someone's 20 page essay on how SLIME is the best thing ever. Haskell gets into odd stuff with ghci, cabal, and stack, and all of them are extremely slow.
- Tutorials: Python has a ton of them, they all get you printing to stdout and calculating things in about 10 minutes. Scheme / Racket typically spends multiple chapters navel-gazing about lists, cons, and such. Haskell is actually better in terms of the Hello World stuff, but ghci v/s ghc bites you again; and no one has a clear idea of which one to use.
- Advanced concepts: Python has mainstream but halfhearted OOP; and things like decorators and metaprogramming. Quickly intelligible if you learned something else like Java or C++. Or if you learned shell scripts you can get quite a bit done with just imperative. Racket/Scheme: 3 chapters in and you're still trying to figure out tail recursion. Haskell: Instead of just doing fun things with take and foldl you're being hit with trivia about typeclasses.
You’re replying to a post making assertions about beginners.
That doesn’t usually mean people with 4 years programming experience picking up a new language.
Racket: criticizing for having a beginner-friendly IDE doesn’t make a lot of sense. There’s always Magic Racket for VSCode for the others.
I guess you’re not starting people with “How to Design Programs” because that’s pictures and animations for ages.
Haskell: that was funny but an absurd criticism ghc vs ghci?? Nobody has that problem. The other stuff - valid but lead with it instead of trolling.
Back when I was a beginner actually interested in getting out of the beginner step of Haskell, this was an issue for me times. So there's at least one person :)
Also anecdotally I have seen people ask this in Freenode #haskell as well (the “Freenode” probably tells you how long ago this was) ; and there a few issues [1] and [2] where I see beginners having the same/similar issue. The second one is particularly funny, 4 people give 5 solutions and no one seems to know what the actual fix is. Instead you have people arguing whether a repeated do works or not. This would never happen with Python, just saying :)
> Racket: criticizing for having a beginner-friendly IDE doesn’t make a lot of sense.
Sorry, perhaps too harsh but I don't think it's as beginner-friendly as you think. I think it would probably help if they made the design more modern and welcoming. All these details about you can rewrite entire languages in Lisp and we can't even at least get a GUI that looks like it was written after 2007?
---------
[1] https://www.reddit.com/r/haskell/comments/1kfym5s/difference...
[2] https://www.reddit.com/r/haskell/comments/18yj7i5/i_have_jus...
Can’t take credit for the quote, read it somewhere.
The whole language changed when they kicked what’s-his-name out, and it’s a tool I almost never reach for anymore, whereas 15 years ago it was my Swiss Army knife.
for all the hate js used to get, py is at least a few magnitudes worse.
my opinion ofc. don’t get mad xD
There's a lot of annoying issues with Python, but compared to the billions of dollars and thousands of man hours that has been spent trying to fix Javascript and how horrible it still is, it's a perfectly cromulent language.
Did you encounter JS first?