Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

One obvious reason is Python's extreme readability, it has often been described as being as close to executable pseudo-code as one can get.

If you're using an LLM to write code I think the rules would be

1. Use a language you know really well so you can read it easily, and add to it as needed.

2. Use a language that has a large training set so the LLM can be most efficient.

3. Use a language that is easy to read.

If your language has a small training set or you don't intend to do much addition or you don't really know any language that well or are restricted from using choice 1 for some reason, 2 and 3 move up, and python has a large training set and it is easy to read.



Python is locally readable. Reasoning about larger systems in Python is where things get really hard, because you have to describe how many small individually readable things interact with each other in a very limited vocabulary.


For larger systems you create your own modules and abstractions, so comprehensibility at higher level does not depend so much on the language.


The tools the language gives you to create those abstractions make a lot of difference, however.


But every abstraction that an LLM has to write is a choice. Your way of writing Python may not match that choice. The next run of the agent might not choose the same way.

Because the language gives you many different tools, an LLM generated codebase can get inconsistent and overly complicated quickly. The flexibility of Python is a downside when you’re having an LLM generate the code. If you’re working in an existing codebase, it’s great - those choices were already made and it can match your style.

When an LLM has to derive its own style is when things can devolve into a jumbled mess.


To me applying LLMs to a python (or similarly dynamic) code base where it’s currently spaghetti and monkey patched, it can miss things just like I can.

But… I have to admit Opus 4.7 has been very pragmatic in detecting root causes and proposing sensible fixes to bugs in this situation (ie bugs encountered in production not compile time).

It’s also fine at matching current styles and conventions (which is great if they are good styles and conventions).

In terms of new code, rust would have been near impossible to write with such a high degree of non-local reasoning, so I’m assuming these bugs wouldn’t be present.


The larger models really are more reliable at following instruction and reasoning their way to solutions. I haven't found that the harness makes that much difference. CoPilot, Claude, Pi, all see similar results for me. What really does make a difference is clean task separation and a clear plan / todo / implement workflow. I've consolidated a lot of the way I work with agents in https://www.agentkanban.io - the task board keeps the tasks discrete and minimal. I built in plan todo implement into the agent instruction that binds the board task to the chat.


That’s why proper using LLMs on large python codebases establish coding standards docs and tests. Turning the LLM loose is chaos, but having clear arch and naming and other standards can get pretty consistent results.


Name one of those abstractions that is missing in Python.


You joking?

- strong typing - real concurrency (heaven forbid you want a background task without having to spool up an external message queue and worker) - immutability - limitations in error handling (sort of just typing really) - limitations in nullability (also typing) - memory layout is usually hidden or abstracted away - no actual private methods or classes

That's far from a complete list, but maybe you're taking for granted the typical pythonic conventions that many practice. It requires a ton of work to design and architect python systems of any non-trivial size for maintainability and understanding. No language is perfect, but there are plenty of languages that make supporting complex systems easier than python.


> strong typing

Python is a strongly typed language. Strong and Static typing aren't the same thing.


You are obviously correct, but even if we let aside parent's confusion about strong/static typing, it's a weak argument.

Python does provide type annotations and extensive tooling to make static analysis, so this whole "missing abstractions to help with understanding" is simply false. You can even setup a python project to make annotations mandatory.

There are plenty of things to criticize about Python - performance, packaging and multiplatform distribution come to mind - but to think that it is missing the tools to help build and understand complex codebases is frankly absurd.


In all the years I used Python at startups and firms, there always was extremely heavy resistance to using types correctly if even using them at all. Not one of the firms would have passed at even 80%. Moreover, me encouraging its use was always met with antagonism. In summary, Python types are a disaster for code comprehension and maintainability because they're optional. So you're right that Python has the tools, but wrong overall because you shouldn't be needing tools for something that should be a default.


You are moving the goalposts. The point is that the abstractions exist. You can use them if you want and they will help you to build an understanding and managing complexity if you do.

If you inherit a complex-but-working python code base and you think that types would help you, getting an LLM to add type annotations and enforce checking is certainly less work than "rewrite it in Rust".

Plenty of teams in startups will ignore automated testing as well, it does not mean that python is lacking the tools for it, nor does it mean that a hypothetical language that mandates 100% test code coverage would be better to "build understanding" or "managing complexity".


You are ignoring what actually matters on the job in the real world wrt code maintainability. It is impossible to get an LLM to correctly add many missing types since it's not clear at all what many of the types ought to be, and because different parts of the code have vastly different expectations (due to bugs) of the types. Should the LLM then support the bug or should it fix it -- it will never know for sure since it takes the code as a precondition. The vast majority of commercial Python code out there is truly horrible considering it is lacking type definitions and enforcement.

I rarely actually care about tests if the code is written clearly and with good logging.

Python doesn't enforce discipline, so anything goes. While this personal freedom is good in a religious sense for one's own project, it's disastrous for code that requires development by a team. Some programming languages are just better than others for team development. I say this as someone who benefited from Python professionally for a decade.

There also are more unrelated severe problems with Python, e.g. no official container for no-GIL (free-threaded), thereby making real parallelism impractical.


> it's disastrous for code that requires development by a team

Honestly, my experience over (mumbles) decades has been that this argument has been trotted out hype cycle after hype cycle for different paradigms and languages, and it's never really true.

Teams can ship totally fine with just about anything. Teams can find ways to fuck up just fine with just about anything. Nothing really adds an appreciable overall positive over other alternatives in a global sense. The hard parts are always the hard parts. Most code still winds up kind of horrific but yet "good enough" for whatever business purpose is being met.

Peoples individual tastes differ and change over time, so they may feel these claims are true. But the folly is in projecting it onto others.


I think both things can be true. Obviously a competent professional in any industry (not just software) can make shoddy or inappropriate tools work well enough. Obviously an incompetent or only barely competent or competent but pressed for time professional can screw up with even the most carefully designed highest quality tools.

But I also think it's clear that tool design impacts quality, safety, and efficiency. Programming languages aren't an exception to that.


> But I also think it's clear that tool design impacts quality, safety, and efficiency

Yes, to an extent. And it's also the case that it usually doesn't matter. And that's my point.

I have also been someone like GP poster who has declared that it's physically impossible to produce valid software with XYZ tool in a team environment. And yet, there are oodles and oodles of counterexamples in the real world that proved me wrong and it worked AOK for them.

Could they all have been better off using another tool? Hypothetically yes. But their business needs (or whatever) were met and thus disproves a claim it can't be done.


Business needs can be met in the short term only so long as the original developer of the project stays in the team. As soon as they leave, when excellent type definitions and annotations are missing, the project terminates because it's simply unmaintainable. I have seen this happen countless times. In other words, the deliverable will in the short term fool many clients who don't know better, but it is ultimately a scam.


You're saying two different things there.

> it usually doesn't matter

This is what I'm disagreeing with. I can hammer a nail with a rock well enough in a pinch but extrapolating from that to "it doesn't matter if we save some cash by equipping our carpenters with rocks instead of hammers" is obviously wrong.

There's a whole continuum of less extreme examples of the same principle. The quality and purpose fit of your tools absolutely does matter but in the case of programming languages it's a bunch of nontrivial tradeoffs that vary from one project to the next so it's all quite fuzzy.


> I can hammer a nail with a rock well enough in a pinch

The original post to which I responded said "it's disastrous for code that requires development by a team". Anyone claiming that using Python in a production environment is "disastrous", or equivalent to hitting a nail with a rock, is being obtuse. It has and continues to happen all the time with no notable ill effects. It's not like these teams are using Brainfuck here, Python is one of the most mainstream languages in the world, and I don't think I need a cite to make the claim that many, many teams manage just fine with it.

When I said "it usually doesn't matter", i'm talking in terms of the most important metric for a team: are the business goals being met i na timely and cost efficient manner. And my experience has been that as much as I've been a zealot in the past claiming that this tool or that tool can't possibly achieve useful results, teams that do use those tools still manage to achieve their business goals. Meanwhile I could also look around and find plenty of teams using whatever the flavor of the week "ideal" tool is and find teams that aren't meeting their goals.

Now, in an absolute objective sense, is it true that some tools are better fit for some purposes than others? Of course. Is it true that some languages lend themselves to robust coding practices than others? Of course. But the world's not a vacuum, and one must do the calculus at a higher level because as I said, the most important metric for a development team is achieving business goals. Would adopting tool A over tool B (for any A, B) improve the business? That's when these questions get a lot murkier, and the relative advantages & disadvantages tend to drop into the "noise" category.


I agree with you that it clearly works well enough in practice and I agree with you that it's murky - specifically I believe that there are substantial upsides provided by the language and its ecosystem.

> It has and continues to happen all the time with no notable ill effects.

But that statement of yours is patently false. The ill effects of duck typing and extreme flexibility in the face of massive code bases and large teams are incredibly well documented at this point. Literally the entire driving force behind typescript is directly analogous to the situation in the python world.

You might as well claim that concurrent programming in C or manual memory management have no notable ill effects. Even if there are places where you think they make more sense clearly they bring lots of fairly serious issues along for the ride.


We're using different metrics here.

Can it cause bugs? Yes. Do teams ship production code that meet their business goals? Also yes. The former doesn't necessarily preclude the latter. And as long as the business keeps on trucking along, complaining about the bugs and headaches is just a matter of engineering sensibilities. Which I agree with fully and grind my teeth every time.

If the business proceeds along just fine, having the perfect temple of dependently typed, category theoried, memory checked, fuzz tested software may have turned out to just be a waste of money.

If, on the other hand, the business does not proceed along just fine because the team can't get anything done due to not being able to understand that a float probably shouldn't go into a variable that's supposed to be a string, then yes, you're right.


Huh. If you're going to be blind to the science, then the team that you're in will continue to ship garbage code until finally one day they burn down the house. Feel free to bury your head in the sand, but don't drag us down with you. Preaching ignorance and apathy is what you're doing, and it doesn't relate with those who actually have standards and hold oneself accountable.


Not only your whole argument is pure conjecture, it's completely orthogonal to my original objection. People are just throwing completely silly takes as "python does not provide the abstractions to build and manage complex codebases" and this is demonstrably false. Let's just drop this line of discussion, because it's getting beyond ridiculous.

---

The funny thing is, I mostly agree with the core premise of the article: shipping today a functional proof of concept in Rust is not that more difficult than doing it from Python, and Rust has become the default choice for high performance libraries, so one might as well just go all-in Rust. But this has a lot more to do with real shortcomings of Python (performance, packaging and multi-platform distribution) than "Python does not provide the abstractions to manage complex codebases".


Your original objection is altogether irrelevant. It and Python miss the point of what matters, which is the end result in teams. And I never actually said Rust; you did. Rust is not the answer to everything. It is easy to spot a religious zealot as you are for Python -- these people are the worst for the Python community as their blindness prevents from making the hard changes necessary for keeping up with the times.

Using your logic, someone could similarly argue that C is a perfectly fine language if used with appropriate tooling which checks for errors, but it would be a similarly bogus argument.


The thread started with "Python lack abstractions to help thinking n large scale systems".

I am not saying Python typing story is perfect in reducing errors or making code safe, I am just saying that the abstractions to "help manage large scale systems" are there.

No talk about "the end result in teams". No talk about "adoption on startups". I just called out a ridiculous, demonstrably false claim and you for some reason want to completely redefine the discussion around your opinion.


For the record, what I stated is fact, not opinion. Python is a fine language for the disciplined lone developer, but a terrible one for most teams. And it is not up to you to suppress this fact as you surely seem to want to do.


If you want to make the case that Python is too flexible and it does not have guardrails for less experienced developers and undisciplined teams, I'd agree 10000%. I'm still traumatized by my time working in an academic setting and having to make sense of some bioinformatics packages.

If you want to make the case that some other language makes a better fit for a world where LLMs and people can work at the same time and need to deal with complex codebases, fine.

You can even make the case where language expressiveness is less desirable now that LLMs can deal with implementation details and "engineers" can go by simply with English and UML.

These would all be interesting arvuments and worthy of a conversation. But again, this has nothing to do with the original point of the discussion.


I am not going to sit back and let you fool users into an incorrect conclusion falsely insinuating the safety of a Python project when I know that it isn't safe due to the pervasive poor team discipline that hounds most teams. You're just complaining that your scam got busted.

I think Python could be okay as long as appropriate tooling is aggressively added to the project right at its start, with strict CI enforcement. At that point it residually becomes a culture issue which remains poor.


> let you fool users into an incorrect conclusion

You continue to argue over something that was not on the table. That tells me that you just have an axe to grind.

> At that point it residually becomes a culture issue which remains poor.

Ok, so we are clear that the language itself is not missing the abstractions. I guess that's all I wanted to hear. Thank you, we are done.


The culture issue is unfixable. Python attracts good engineers but it overwhelmingly also attracts bad engineers who don't give a rat's azz about code comprehension and maintainability. These engineers last long enough to get a new job elsewhere, and the ones left are holding the bag. Type-enforced languages seem to avoid this problem. I am willing to bet that type-enforced languages have a lower rate of failed projects that last less than four years.


Holy crap, you really can not take the hint!

> Type-enforced languages seem to avoid this problem.

Right, we all know how typescript projects are known for their longevity and we all know that people working in typescript are doing it because of their exceptional care about the craft and concern about maintainability. It has nothing to do with employability or the fact that startups:

- favor agility and time-to-market over long-term maintainability (i.e, they accrue a lot of technical debt)

- are more budget constrained and less likely to have enough resources to focus on cultivating good engineering discipline.

- have to compete with everyone else to attact talent in the labor pool and can not all afford to choose a tech stack that is less popular.

- will have a wild variance in the quality of the average developer.

No, sir. None of this really is really important to understand why startup teams have crappy code. It's all about the choice of statically- vs dynamically-typed languages.


I am afraid the issue isn't limited to startups at all. I have worked at bigger firms too, those managing trillions, and they have the same issue for some of same reasons, e.g. agility, low wages, etc. The poorly-typed Python project goes to shyt in the same ways at them too.

I won't speak for TypeScript since I don't have comparable experience.


So, you are all pissy and judgemental against Python claiming the issue is with its type system without looking at other widely popular languages that has stricter type checking? Really?!

you probably mean that python is not static typed.


So, the abstractions are there, you just happen to think that the implementations are flawed or limited. This is not the same as claiming they are lacking.


No, they're not there. Did you read my comment? It's not just flawed or limited implementation, those are things that python just doesn't have.


It absolutely does.

- Typing annotations + mypy can completely help you build and understand a complex system. WIth pyright you can even analyze code that is not annotated. The tooling that enables developers to design and conceptualize their application around the type abstraction is there. You make it sound like people can write`x = "2" + 20` in python like in Javascript or PHP4.

- Concurrency: take your pick of multithreading, multiprocessing or asyncio. The abstraction of a thread model is there. The abstraction for an event loop is there. Would it be nice to have something like the Actor model as well? Sure, but to go from that to "python does not have it" is a completely wild take.

- "No actual private methods or classes": I mean, really? Obviously classes are supported. You can create different classes by composition, you can create a hierachical structure. You can use Protocol to define types that must implement interfaces. You can define functions that are overloaded and you can have method dispatching. All of these ABSTRACTIONS are provided. It's not because they are not forced on you that they don't exist.


Not the person you replied to, but I think the point is that it isn’t really that interesting to point out that you can achieve certain things in Python with enough diligence.

Practical experience shows that languages that force some strictness about things that are known to be sources of trouble as complexity grows unsurprisingly make it easier to manage those sources of complexity.

It is vastly easier to write a performant, multithreaded program in Rust than it is in Python. That doesn’t mean it is easier to write all programs in Rust than in Python - it isn’t.


There might be an argument to be made here, but this is a completely different argument than saying "python code is only readable locally" and "Python does not provide the abstractions to build and understand complex applications".


As far as I know python type annotations are not enforced at runtime, these are really just helpers or extensions to your local dev environment

It's interesting to me that Python requires third party tooling (mypy) but we are still giving credit to Python that it has all the tools it needs

Yes, complex systems have been built in Python but that's despite it's tooling not because of it

Our python applications are all mypy, and we have been experimenting with the uv solution as well. I'm glad that Python has type annotations and classes but it sure doesn't feel the same as a statically typed language


> As far as I know python type annotations are not enforced at runtime, these are really just helpers or extensions to your local dev environment

But it is still a feature of the language. Try running a type-annotated python module on a python 3.4 interpreter, it won't work.

> but it sure doesn't feel the same as a statically typed language.

Again, that is totally a defensible position but an entirely different argument than the ridiculous "Python is only locally readable and does not have the abstractions to help understand large scale applications" line.

I am not here to make a case that Python is the ultimate language and that it is without flaws. Quite the opposite. I am porting some of my FOSS projects to typescript and Rust because I ultimately agree with the premise from the article. The only reason I am here in this stupid discussion is because it's 2026 and we still have some pretentious know-it-alls who think that Python is just some "scripting language" which can not be used for serious work.


I find the class (C++-descended languages) as the primary abstraction much easier to reason about than the module (Python), and I'm not sure why. Could be familiarity of course, but I think it might be because a class has a more explicit contract with the outside world. It's more rigid.


Abstractions are created to improve local comprehensibility. They introduce a cost for global comprehensibility.


hmm, yeah given LLM's ability to churn out lots of code quickly and be overly verbose in that code that is a potential downside. That it could in a quick one time edit create so much intellectual overhead that Python might be the wrong language to understand what is going on.

What language do you feel is easier to reason about in the large?


Haskell would be my vote, and Rust too, actually, both because of their very strong type systems. The type system lets you very quickly figure out what something is before you figure out what something does, and it turns out that separating those two concerns as hard as those two languages do often results in doing the whole one-two punch faster.


Bit of a nit, it isn't the strong typing that makes Rust great for LLMs, it's the very strict compiler.

Plenty of languages have strong (enough) typing but their compilers happily let you or the LLM footgun yourself.


Same reason Zig is great for LLM's


Oh, that's fair.


Haskell does not qualify for a large training set, though. (Nor for readability in my opinion)

I think I have never seen haskell software made wih LLM's but well, aside from university, I have not seen Haskell code at all. (Also Haskell purists I would associate with people who avoid LLM's)

I would rather go with Rust given these choices.

But I have good results with typescript (or javascript for simpler things). Really large set of examples. Tools optimized for it, agents debugging in the browser works allmost out of the box. And well, a elaborate typesystem.


I used Claude that created a terminal based table viewer from rust first, to lean , and finally to Haskell. https://github.com/co-dh/tv-hask/tree/main

I give up rust because it’s not functional enough. There aren’t many things Claude can prove about a table viewer, and Haskell fits very well, and have enough libraries. Claude is pretty good at Haskell. I barely write Haskell before but I do know monad.


I used Claude to generate Haskell and it works really well. Claude struggles sometimes with respecting abstraction boundaries, but Haskell enforces parts of those boundaries in its type system better than a lot of other languages (if a module can’t do IO, for example).

Works well, in my experience. Sometimes the agent does weird stuff that you have to rewrite, but I get the sense that this happens in any language.

Maybe Haskell’s training set is not large enough, but it seems to work despite the smaller training set.


How much code do you think is necessary for LLMs to be good enough?


In the window of Haskell-like and highly readable, I’d throw OCaml and F# out as strong candidates.

In practice your code can be cleaner than Python, deeply flexible naming capabilities including full sentences with backticking, efficient and powerful discriminated unions and types enable near-English domains, the type system keeps you honest and provides exhaustiveness guarantees, domain modules of applied functions are obvious and locally coherent domain grammars, and there is potent DSL support to create mini-grammars for legibility and expressiveness.

I used to write python by hand to reason then type it up in C#. F# is just as easy with a pen, but far more powerful and with a powerful type system and aggressive compiler. OCaml and F# are also highly token efficient languages, beating Python across the board for agentic work.


If you're going to go Haskell, why not go all the way to Lean 4 and get mathematical provability along with reasonable speed and type-safety?


I’d add perl (similar runtime semantics as python, but at least sigils give you some hint of developer intent. If you see &@%$$ck() in perl, you know you’re in for a ride).

I’d also add, C, C++, Rust, Java, Swift, Typescript, Ruby, Lisp, Make, Awk and Sed.

The only thing I’d rate a tie is Javascript.


Wouldn't a LLM just produce a massive type gibberish long term?


I've "written" a lot of rust via LLMs, and the rust tooling and features give a lot of useful guard rails to LLMs that produce pretty good code overall, certainly compared to the python I've seen it crank out. Clippy and fmt alone often cause the LLM to hit a snag and realize it's mistake and take a better approach. It's quite a powerful combo IME


There are many languages with similarly strong type systems - Scala, Kotlin, OCaml, etc (and nowadays, even Java). A GC may also be an advantage in that the LLMs may get it right in less tries.


I'd say Java, because it has a massive footprint amenable for training, and a strong type system (does not have sum types though and those are trendy).

You'd have to steer the LLM to use the style you want, and not massively overarchitect things though, but that's going to be an issue nonetheless.


Java has sum types - they are fairly recent, called sealed records, and can be exhaustively pattern matched on.

(I do agree however, Java is a great target for LLMs)


C# is as close to an ideal language as you can get for most things IMO. I find AI does a great job with it.


I like C#, it's how I make a living, but it's way too large today. I can program in valid C# and it looks like C or I can program in C# and it looks like a functional language or I can program in C# and it's looks all angle-brakety like C++.

The problem with that is everyone has an opinion on what good C# looks like.

For personal projects, I'll take a much simpler language any day.


C# has recreated the C++ dialect conundrum. For some it’s effectively an idempotent functional language with unfortunate failings of exhaustiveness, for others it’s Java ca 2009, for others it’s C++ but not quite.

Discipline, effort, linters, reviews, more discipline, more effort, retraining, discipline… and foot guns everywhere because so much of the adaptation has been a 95% solution. Personally I got everything C# promises even now when F# was dropped years ago and have found the interim pretty annoying.


While C# is a particularly egregious case, I think all reasonably long-lived, popular languages suffer from this problem. Go is being very intentional about not falling in this trap, but JavaScript, Python, Java.. modern/idiomatic code in all of these languages looks very different from the code you'd write using them 15 years ago.

At my workplace, we use the .editorconfig and static analysis heavily to push us towards a consistent C# feature-set and style. This plays the same role that pyupgrade would in python, for instance.


I do agree. C# is an hidden gem for IA. There are not that much different ways to get somewhere so the model have probably been trained on the framework and libraries everybody uses (the Microsoft ones).

Compared to most languages, including Java, C# will have a hard time letting you compile incoherent code.

You barely need any dependencies other than aspnetcore and efcore for most applications and your AI knows them well.

It’s easy to do TDD with it so it’s easy to keep your IA from hallucinating.


I definitely agree with the sentiment. However this part.

> There are not that much different ways to get somewhere

This is far from true. C# is a language where you can operate on the raw pointers through unsafe keyword. On the other end of the spectrum, you can have duck-typing in dynamic blocks.

For operating on collections you can use old style loops, or chain of lambdas or sql like syntax.

I have been coding in C# old school way for most of my life at this point, and I feel like I'm in a foreign land reading code from some other C# projects.


get LLM to write ADA and have it use SPARK for verification.


Although it's not part of core Python, tach is pretty handy for specifying and enforcing those larger-scale interactions: https://github.com/tach-org/tach


Yeah, that's cool, but it would be almost completely unnecessary if python just had actual private methods/classes/properties. It's a lot like pydantic, which is completely unnecessary if you had strong typing.


This is why good design documents will always be necessary.

When I work with AI I always have it keep an up-to-date architectural document committed to the repository.

Also, we need to be able to understand what is happening under the hood somewhat, so I very much agree the readability is crucial. And frankly, rust is not up there in the readability realm.

I think all the previous language designs still hold for their respective use case. AI written or otherwise. Why? Because performance acceptability is domain specific, and also the algorithms complexity generally determines overall performance.

For example, move the performance critical stuff into a Python C extension like Torch etc…


Locally readable is what I want for LLM-generated code, though. If I need to change the whole architecture, I re-prompt the LLM and have it rewrite the code for me. The changes that I'd need the code to be human-readable for are quick fixes where the LLM got something simple wrong and it'd take longer to explain to the LLM where it went off-track than to just fix it myself.


I’m curious about the design space of languages & frameworks which are lower level than LLM prompts but higher level than Python, Ruby and Common Lisp.

Do you have any recommendations for systems where reasoning about large systems is easier than in python?


You have to go into live programming, code in a system, and saving images. Readability is no longer a factor, what you want is easy access to documentation, quick navigation, and a playground.


Anything with a good, static type system will be an improvement, in my opinion. Types exist to encode invariants in an enforceable way, after all.

Rust is the gold standard among imperative languages, but it’s standard fare among functional languages such as Haskell, OCaml, F#. You can also get really far in C++ if you have the stomach for it.


I have used Rust, Java and TypeScript before, so I understand that static typing is a major help.

But I don’t think types are really sufficient to solve the problem you identified earlier of understanding how “many small individually readable things interact with each other”. Maybe you meant that phrase in a different sense than I read it, but it seems to me that there are still a lot of small individually readable things to keep track of in Rust.


That’s true. Once you have APIs and want to use classes to create larger structures, the language is full of warts.


I have built large systems on python that use classes, for more than ten years. I came to it from Java, ten years.

As a rule, I avoid implementation inheritance. Occasionally I need to facade a library that assumes implementation inheritance to avoid it spreading into my codebase.

When the codebase hits a certain size, I hand-roll some decorators to create functionality like java interfaces. With that done, and a suite of acceptance tests, I find it scales up well.


Python is amazing for scripting.

Python is terrible for writing big systems.

Projects whose V1 is written in Go/Rust/C++ don't normally go out and re-write V2 in Python.

The reverse is really common.

Even many famous Python packages are now Python wrappers.

https://ashishb.net/programming/python-in-production/


> Projects whose V1 is written in Go/Rust/C++ don't normally go out and re-write V2 in Python.

That's because you would usually rewrite your Python program in something like C++ if you realise that it's too slow and you need the speed of a compiled language, despite the enormous extra complexity to create and maintain it that way.

You wouldn't go back the other way because it's very rare to go to all that extra effort writing in a more efficient language only to realise that the slower performance of Python would've been adequate after all. And, thanks to sunk cost fallacy, even someone that does realise it is unlikely to make the switch back.

There's no way you could convince me that writing your program in C++ is easier to code in, even for a very large system, than Python. C# maybe.

> Even many famous Python packages are now Python wrappers.

Of course! That's precisely because Python is much simpler to code in. If your Python libraries are wrappers around native code then you get the speed benefit without having to drop into those languages. (Plus they can release the GIL, allowing true multithreaded Python.)

If native coding languages were good enough then there would be no need for Python wrappers - you'd just call into the native library directly.


That and how many developers who would write first round in Go/Rust/C++ would think it beneath them to write in Python :) The complaints alone wouldn't be worth it even if there was some suprising specific use case.


> You wouldn't go back the other way because it's very rare to go to all that extra effort writing in a more efficient language only to realise that the slower performance of Python would've been adequate after all.

It's UIs which are typically rewritten in more "fun" languages - occasionally because it becomes too much of a maintenance burden when all one wants to do is move around some form controls.


I dont know if the reasoning for a rewrite is purely for maintainability though. Ive used python at scale and its fine if you have reasonably good code hygiene. The reason I'd want to rewrite in any of those languages is they're significantly faster _and_ are maintainable at scale.


> Ive used python at scale and its fine if you have reasonably good code hygiene.

True but that's the problem. Once you have a big enough team, it becomes an uphill battle to maintain that.


If you use the typing system (which I do religiously) Python becomes a lot easier to reason about in larger projects it also makes linters and refactoring tools easier to use.


Maybe I'm just using it wrong, but typed Python seems a long way behind typed JS (i.e. TypeScript).

In Python in seems like there are multiple type-checkers with widely differing levels of coverage, so it's not at all obvious which one to use, and typing is really spotty in third-party libraries. So you can get some level of type-safety but it doesn't feel very dependable.

In TS, there's one canonical checker and the others work hard to stay compatible with it; and typing in third-party libraries is generally very solid. There are still some old libraries without types, but I think those headaches are mostly in the past now (similar to the Python 2 -> 3 switch).


Python is faster to write so obviously you'll see things built in Python first more often than the reverse. What's that quote -- "Better to remain silent and be thought a fool..."


Indeed. Python is faster to write and harder to maintain over the long run.

The "faster to write" advantage becomes less relevant if most code is going to be auto-generated.

The "harder to maintain" might still remain more relevant.


>harder to maintain over the long run.

First off, this is begging the question. Second, if you never get to a point where you need to maintain something, who won?


Exactly. A lot of people forget that Python is just shell scripting++, taken way too far.


I never really understood what exactly is so readable about python. I've been developing in Python for 8 years now, and before that I was a C# developer, and I don't find Python to be that more readable.

Sure there's less ceremony, and yes, you can have your project going with just a single file, but other than that...?


I think the meme come from the fact that in 00s and early 10s most people looked at Python code coming from C++ and Java.

In Java bad OOP conventions were commonplace, like everything using getters/setters, deeply nested class hierarchies and insane patterns like AbstractSingletonProxyFactoryBean. It got impossible to figure out what's going on.

C++ just got every possible feature that badly interacts with each other, in an amount that never could fit in a single person's context window. That basically led to a situation where every programmer or company had it's own dialect of the language; the other dialects than your own were mostly incomprehensive.

Python has it's own share of bad features, and for a long time really bad ecosystem around the language - Python 2 vs Python 3; eggs vs wheels; easy_install vs pip; 123489 ways of installing Python and each of them bad. But, once it started to become better, in the mid-late 10s, around Python 3.5 or 3.6, it exploded in popularity.


Python data processing/ML in the 2010s became a huge asset for the language.


Ironically it also created a ton of really badly written Python in the process.


Commercially, almost all Python is fairly badly written, with types either not documented or not passing with any consistency even when documented. It is the default state of Python. I blame Python for it because it could have made type definition and conformance a default, but it didn't.


The AI boom has really carried Python up with it, but it was quite popular as early as the mid '00s. I remember grumbling in college around that time that the CS curriculum was shifting from Java to Python, because I didn't like Python and thought it was a worse first language.

Incidentally, even though I still hold those opinions, I can admit that history has solidly shown them to be unfounded.


C++ and Java and … Perl.


C# is also a great language, but notice how it have been moving closer to Pyhon-style syntax. E.g. now you can initialize a list like [a, b, c]. They wouldn’t add that syntax if they didnt think it was an improvement.

Less ceremony and boilerplate means more readable code.


"whitespace, not brackets" from a sibling comment touches on it, but a lot of people, beginners especially (but not uniquely), are put off by symbols when reading code. Python is less symbol-heavy than most languages, by using whitespace and syntax and words (eg. `and` not `&&`, explicit `lambda x:` rather than `x =>`) in their place. It doesn't go so far as COBOL as to be cumbersome, but far enough to make a difference to a lot of people.


Reaaaally?

I think a lot of the readability of python is in the fact you don't need to be recently familiar with it to pick up what its doing most of the time.

Over my career I've dipped in and out of rust, typescript, perl, swift, etc codebases. I'm no expert in any of these, but every single time I have to look something up to understand what this set of arcane symbols or syntax means.

When I dip into Python I just ... read it.

(None of this is to say I prefer Python, just that I really do get the readable thing)


I dunno, as someone who doesn't program in Python, I find dunders to be very confusing. Like, how is this readable?

_foo

foo_

__foo

_Foo__bar

__foo__

foo__bar

All of that is valid Python, and some of those forms mean different things depending on where they are used.


The second, fourth, and sixth form is options aren't used AFAIK.

Otherwise, a leading underscore indicates a private method but isn't enforced. A double leading underscore is also a private method but is "enforced" by giving it an unpredictable name. Double underscore (on both sides) means the function is digging in to python's API, like if you want to give a class some behaviour with + or = or [].

It's not trivial, and not particularly intuitive, but it's not necessarily terribly confusing.


The second form has no built-in meaning, but is frequently used in the wild. Often in local variables to avoid shadowing builtin types (`id_ = get_id()`) and in various libraries. Out of the top of my head, ORMs also use it to mangle reserved names.

edit: I googled a bit and PEP8 explicitly says "Thus class_ is better than clss". and "single_trailing_underscore_: used by convention to avoid conflicts with Python keyword, e.g..."

The fourth form is the mangling used for __x names internally (__x field in class Foo is actually _Foo__x

I don't know where GP saw sixth form, but considering all other forms are from real-world usage, someone probably uses it too.


What do you mean? Those are valid identifiers but programmers aren't required to use them.


I don't doubt that valid Python can include hard to read code. You xcan write gnarly Python, for sure.

But I'd still argue the average Python codebase tends to be pretty legible and simple to read.


The "other than that" is whitespace, not brackets. Whether that's a big deal is up to you, but the carry on effect of that is that the code is indented the way the control flow interprets it, so there are no bugs from misplaced braces. (Plenty of other bugs for other reasons, unfortunately.)


I find brackets help me understand structure from a distance much better than whitespace.

Misplaced brackets seem like a thing from the past to me when we didn't have IDEs. I don't remember ever having a bug due to that.


> I find brackets help me understand structure from a distance much better than whitespace.

I can't imagine how. Whitespace physically lays out the block structure on the screen; braces expect you to count and balance matching symbols, and possibly scan for them within other line noise.


This is a 00s POV. If you spend any time on syntax formatting in 2026, you're wasting it. It's a solved problem.

Any reasonable language with braces has standard formatter that will just put each brace level on a different whitespace level.


Yes, and so will any reasonable text editor automatically indent to the most likely position, and remove an entire indentation level with backspace, and substitute spaces for tabs per community standards, and keep everything lined up neatly.

But GGP was making a claim about the braces themselves solving the problem, and they clearly do not. The indentation automatically inserted by your tooling solves the problem. And it's at least as easy to communicate the intended block structure with colons and backspaces as with open braces and close braces, plus it doesn't waste lines (or invite bikeshedding) for the closing braces.


Nevertheless it happens that while moving code around one wonders what indentation level that code should go. Undo, undo or git show the original code, look at it, retry more carefully.

Brackets would allow the editor to autoindent the pasted code.

No choice is perfect.


Working in C# i feel basically still read code structure by the visual block structure / indentation. I dont think I've ever counted braces in my professional life. The IDE makes sure it is formatted correctly and ambiguity is basically impossible.


Exactly. So if the indentation is the actually salient thing, why not use it directly?

I mean: you don't count the braces because your tooling counts them and makes the indentation match what Python would use anyway. If you had just created that indentation in the first place (which with a proper editor is at least as easy as typing the braces; you essentially type : instead of {, and backspace instead of } ) then you'd be in the same place, except without the extra punctuation noise (well, with half of it, because GvR thought the colons were a useful signal even if redundant).


Whitespace and braces work together to make the code more readable; both by the computer and the human. And they make it less likely to have errors, because the braces convey intent (much like parens in math when they're not "needed")


So you would find bracketed code without any use of indentation easier to read than python?


It's no more 1990, when Python was born. Editors have been automatically indenting bracketed code for a long while. Probably notepad doesn't, or maybe plain vanilla vim.


The comment I replied to stated brackets helped them more than indentation.


Whitespace forcing proper indentation practices has always been one of my favorite aspects of python. I TA'd a data structures in C++ class and the lack of proper indentation making code unreadable was my biggest pet peeve. I always made the student fix their indentation before I would help them debug it.

I know that is mainly a beginner coding issue, but never having to deal with that issue was always one of the biggest advantages of python.

That said, I believe a lot of the stuff that was added in 3 and beyond (to make it more typesafe, accounting for unicode, etc) has made it a lot less readable over time. You can argue that it has made Python a better and safer language, but the pseudocode aspect has gotten worse. I kinda miss that.


Python and C are the only language in which I have experienced that class of bugs. And that is due to if statements without brackets in C and because Python has meaningful indentation which people have accidentally messed up when refactoring.

And today with autofotnatters I think only Python is still vulnerable.


If you are messing up indentation accidentally during refactoring there is either something wrong with your tooling (including your text editor) or you are letting things get too far out of hand before starting the refactoring.


It's 2026. I'm using Jupyter notebooks in Databricks. Guess what my tooling (including my "text editor", the Jupyter notebook), does not do?

Yes, I can castle-[ to shift a block of code left or right, but this is not always problem-free nor is it automatic nor does it have any sense of where the indents should go.

Yes, there is a "format python properly" button which often errors out says "there is an indentation error in your python so I cannot automatically indent it"

Would I like to use better tooling? I present my .vim file as evidence. Am I using what they tell me is state of the art? yes. And in 2026, state of the art does not solve python indenting, because python indenting is inherently a broken paradigm


> Would I like to use better tooling? I present my .vim file as evidence. Am I using what they tell me is state of the art? yes. And in 2026, state of the art does not solve python indenting, because python indenting is inherently a broken paradigm

I don't know what to tell you. I use Vim and find it trivial to get the indentation right using my distro's stock config.


Does your tooling not allow you to select multiple lines of code and press Tab or Shift-Tab to indent/dedent the entire block?

It usually only takes me a 1-5 seconds to fix the indentation when I copy/paste code that existed at a different indentation level. This is not something I'd complain about, personally.


Ah, the old "you're doing it wrong" argument. Moving code from one place to another (copy/paste from online or just from one file to another) is a fairly common source of bugs for a lot of people when it comes to Python. At some point, it becomes clear is an issue with the language, not the people.

I enjoy Python, but the significant whitespace is _not_ one of the reasons.


> Moving code from one place to another (copy/paste from online or just from one file to another) is a fairly common source of bugs for a lot of people when it comes to Python.

I genuinely don't understand how they manage this. Worst case, you paste at column 1, re-select and tab such that the baseline is appropriate for where you're pasting it, which is obvious. But more importantly, you shouldn't be copying and pasting unless you're proficient enough to fix such mistakes easily.

I also don't understand how it can be argued seriously that braces avoid the problem. If you'd paste at the wrong indentation level, why would you not equally well type the wrong number of braces?


There are plenty of python bugs from mis-indented code. Particularly given multiple parts of a flow that "else" can apply to.... for/else, while/else, if/else, try/else and so on. It happens quite often in python codebases I've seen.

Also, good automatic formatters (gofmt, rustfmt, etc) also indent along control flow lines, so without the braces you just changed a syntax error into a "hmm, this is acting really strangely" bug-hunt by using python.


I agree, especially very "pythonic" structures if overly shortened are hard to decipher especially if you don't use or read python on a regular basis.

Often times when I am reading a medium or advanced python codebase I need to look into the function definitions and operator documentation to understand what is supposed to be returned. Where with C-like languages I feel it is easier to build that context because there is more context written and less tricky syntactic sugar.


> if overly shortened are hard to decipher especially if you don't use or read python on a regular basis.

Sure, but this is the case for any language.


If you're doing non-CS academic research and you get only one course/module to teach the new grad students "programming", python it is. That you can get a project going with 3K LoC in a single file is a bonus in academia :)

The scipy/numpy dataframes model is really neat though, python's has all the cool machine learning features, and since they're just a wrapper around some C++ and FORTRAN, it runs fast too if you do things properly.


" and before that I was a C# developer"

So .. you were already trained in reading abstract.

A beginner on the other hand sees lots of intimitading {} in C family languages everywhere. And Python does not need them and less is usually better in design.


Python USED to be easy to read, before a lot of the newer features like type hints crept in. 20 years ago, Python looked like executable pseudocode.


I agree. My kotlin is readable. The functional code with typing all the way tells what every step is doing. My same code in python is a hot mess of nested list comprehensions and lacking lambdas.


Well yeah.

Dropping the ceremony means all that’s left is the ideas and the intent of the code. Which is exactly what you want for optimal readability.


People confuse having fewer keywords/concepts to learn for readability, which is not really the same thing.

Someone who is equally expert at Java and Python will probably consider Java to be more readable.


The concept of "readable" is not really relevant for experts, because, well, they are experts. Being an expert automatically means you can read almost any line of code and know everything it does.

Everyone else appreciates and is more efficient working with code that is intuitive to grasp.


I have many years of experience with Java, and rarely use Python... and I'd say Python is, in general, easier to read. There's generally a lot less "having to go look at _other_ code to know what _this_ code is doing".


Other than that? Exactly that!


My preferences are always Go first and Python if there are specific libraries that make my life easier.

Go is a simple target for LLMs as the language has changed very little and with the Jetbrains go-modern-guidelines[0] skill the LLM can use the handful of recent additions effectively

And with Python there are things like ruff and pydantic that can enforce contracts in the code.

[0] https://github.com/JetBrains/go-modern-guidelines


The folks I work with rave about how well the LLMS work with Go.


Python is great at AI code gen for a combo of reasons: big stdlib, readable, 3rd party libraries to do most anything with great online documentation, big mind-share and presence online.

The big one to me is that it's interpreted. Claude Code does these wild `python -c` "one-liners" that end up spanning a hundred lines or more. It's so ingrained that it does this for solving general problems to create on-the-fly system reports, not just when you specifically are using it for Python development.

One of my more interesting experiments has been "mirroring" a Python codebase I maintain with a synchronized one in another language the AI maintains.


> 2. Use a language that has a large training set so the LLM can be most efficient.

I seriously doubt this is really the case. From my experience coding agents just love writing bad python code. It always needs explicit instructions for example to use uv instead of raw dogging pip. There is a lot of python code out there because it is being taught as a beginner language and because of that there is necessarily a lot python code written by beginners. That's my explanation at least for bad LLM generated python code.


I think this is where D language make an excellent alternative to Python for AI assisted coding [1].

1) It's a very consistent language even if you compared to the other popular languages namely Python, Rust, C++ and Go. Try to perform doubly linked list with them and compare them all [1].

2) It's probably the most "Pythonic" among the compiled language according to Walter.

3) It utilizes GC by default, you can also manage your own memory and you can hybrid.

4) It compiled fast and run fast, heck it even has built-in REPL eco-system.

5) Regarding the small training set, with recent self-distillation fine-tuning approach it should be good enough, D (actually D2 version) has been around for more than a decade [2].

[1] Looking for a Simple Doubly Linked List Implementation:

https://forum.dlang.org/thread/osmecwfnpqahoytdqpkr@forum.dl...

[2] Awesome D:

https://github.com/dlang-community/awesome-d


I would assume it's important to know what's in that training set too

Because I get reliable generation out of "niche" languages already

Is it code with lots of SQL injections used in a different domain to your own?

It's maybe not good to conflate quantity with quality


This is dated, but a professor told me that LLMs are really really good a generating bad pandas code because it's been trained on so much of it!


No, I think the argument from the article is pretty good. Use a language that has a lot of guard rails built in.


or a compiler that makes the llm sad


Disagree, it's verbose, but it's full of needleslly verbose stuffs, use many _ for everything and the rest, and other opaque conventions. Not that any other dev ecosystem is free of any of these issues, but Python just don't shine much on them. If anything in term of script language, Ruby provides a far more solid ground for compact and readable exposure of ideas through something close to prosaic expression.


As much as I dislike writing Go, I think it's pretty close to the ideal LLM language. There's usually one very obvious correct way to accomplish things, there's a ton of training data, it's GC'ed, the standard library is expansive and of good quality, there's a large ecosystem of 3rd-party packages, etc.

About the only place where I don't think Go works for agent-heavy workflows is that it's not very concise. It takes a lot of Go code to express what other languages can do in many fewer lines, and I think this wastes Context Window but also just makes it harder to keep everything in my poor little human brain.

LLMs also do a pretty good job writing modern C++.

I much prefer writing Common Lisp but I've noticed that LLMs (claude 4.6+ and GPT 5.x) aren't nearly as good at writing Lisp than they are at more mainstream languages, plus Lisp's syntax makes it a little hard to read sometimes, especially if you're not in the habit of reading it every day.


I've been using Rust more because of Claude, but I mostly do C# / Python otherwise. I can read Rust, and understand it, but I don't have the patience to fight the compiler, or the liberty of free time. I do however have in my brain plenty of architectural ideas I can convey to a model and get back a sound program.


Python does have a huge training set, but I figure lots of that training comes from disciplines where maintainability or system design isn't as heavily incented. Reports, notebooks, dashboards, etc.

My early experiments with LLM Python seemed to give me that impression, but I'm wondering if it's better now or people have other experiences.


There's a huge difference between a program which can be verified as correct by static analysis, and a program which can only be verified as correct by running it. Python is the latter (though maybe in between with gradual typing). The iteration loop just collapses when an agent is driving an LSP in a statically typed language.


> One obvious reason is Python's extreme readability, it has often been described as being as close to executable pseudo-code as one can get.

But it's LLMs that read it not humans. At least that's the trend

> Use a language that has a large training set so the LLM can be most efficient.

It's pretty efficient with Rust.


But plenty of humans like to be able to read the generated code and understand / edit that.


One could argue that with AI writing so much code, the ease with which humans can read & understand it (for review purposes) is even more important than before.


> ... something you know well and is easy to read ...

For this reason I tell my LLMs to use Ruby whenever possible. In one rare case where the performance of my script was critical, I told Claude to convert the working ruby script to Rust. It got it right in a single shot.


Python outputs is also very versatile. You can use Python to build command line script, web application, desktop app with GUI, notebook with data analysis, or Python package and share with others. It is many ways how Python code can be used by final user.


Funny, I need an LLM to figure out what most people consider "readable" python as its highly unreadable to me. The lack of types, top to bottom flow, and more tends to make it all very confusing for me to read anything python that's > ~1000loc


tbh python seems really unreadable to me, and i'm saying that as someone who's first [non-Scratch] programming language was that. stuff with syntax closer to C or javascript seems easier to see [C?] where stuff starts and ends


Less verbose languages also use fewer tokens, saving precious context.


I personally don’t find it readable at all.


Python also has a rather high number of footguns, which is not a feature of other equally-capable languages.



c llm code is more readable as it probably trained on better code


Haskell is more readable. It looks just like pseudocode. Change my mind.


If Haskell coders could get past their obsession with naming all the important functions using only punctuation characters that might be true.


That’s just ordinary unfamiliarity with a language.


So in short, use Javascript /s


I think that pseudocode aspect is what makes it hard/frustrating to read for me.

I'm more of a c++/TS/etc user, so I miss braces a lot. I think a basic Python script sure it's easy to read through, but a large project starts to get quite ugh.

I am very jealous of Python's numerous built-ins though. I was looking for a JS sum function the other day and was surprised to see node.js still doesn't have a built in + you still cannot reference operator functions.


But at least JS now has a built-in leftpad function ;) (called padStart).


Lmao are people really -ing me because I don't like Python. Tribalism is present in all areas of human life I suppose.

You people should grow up. Programming languages are tools, not pets.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: