Ask HN: How can I get better at writing production-level Python?
I've worked extensively as a software developer in Java before, so I am aware of the many things that go into writing "real" code (as opposed to what one writes for Leetcode or even an academic project), from little things like using the right annotations, to bigger ones like dependency injection frameworks.
I've used Python for Leetcode, scripting, isolated ML work, writing little games, etc., and I've read and practiced much of PEP8, so it's not that I write bad Python code. But I do feel that I could be doing so much better (since I've done better in Java) and I'd like to get to that level of proficiency as soon as I can.
In that vein, I'm looking for any resources that have worked for any of you and you think would be suited for me. Thanks!
55 comments
[ 3.3 ms ] story [ 154 ms ] threadTDD is very easy with Python because the unit testing framework is built in -- I'd suggest writing tests for just about everything you do.
Additionally, the typing system is expanding all the time. Make sure you're adding type annotations where / when you can; even lightweight ones like TypedDict help.
Coming from .NET 6 development, I'll do what I need to do when it comes to fleshing out unit tests, but the brevity of Python unit tests was real pleasant to work with.
Learn all about pytest and how to use its fixtures well.
Mypy for use in conjunction with type annotations for static analysis.
Packaging: Python-poetry.org
Personally, I recommend Deal (design by contract) and/or Hypothesis (property-based testing) libraries, too.
Controversial opinion: Stay away from Flask and all of its derivations. That framework is badly designed. Learn from Django instead.
It's designed as a four-day workshop. Lots of material around 'mature' Python code
I couldn’t of agree more. I’m a Python veteran, but hasn’t done web dev before a few years ago. I picked Flask for one of our web apps and now very much regret it. It feels like it fights a lot of the direction modern python is going. It’s also encumbered by an ecosystem of bloated and under-maintained extensions that only make it harder to use.
Regarding poetry for packaging, I’m 50/50 on it. The product is interesting, but I find myself almost always reverting to a structure where I have requirements managed by pip-compile. It just feels a lot cleaner. I also had a few unpleasant interactions with the poetry devs with regard of GitHub issues, which makes it easier to obviate on a personal level.
I enabled nearly all the rules it has available. And I've learned so much from it.
[0]: https://beta.ruff.rs
mypy brings some of the sanity back.
Clone the package, run the tests, break the tests and try adding functionality. You’ll learn a lot - I know I did when I was starting out.
I’d also recommend checking out Fluent Python.
[1] https://amzn.to/3J48u2J
[2] https://github.com/fluentpython/example-code-2e
But it could be if the coding book includes working examples and exercises, that would probably flag any system looking for code execution.
- https://github.com/python-attrs/attrs
- https://github.com/mahmoud/glom
- https://github.com/pytoolz/toolz
- https://github.com/Suor/funcy
- https://github.com/dabeaz/curio
An honorable mention of norvig's classic essays, which got me into python while I was in college, over 12y ago: https://norvig.com/spell-correct.html.Aside from reading code, _writing_ something that you know it exist (e.g glom) and then comparing it to how others have done it is also a great learning experience.
It is _staggeringly_ dynamic, and basically uses runtime reflection of "static" types to scaffold a really complex ast describing your application.
Don't stretch inheritance where where they are not needed - avoid factory classes unless you know for certain that it's called for.
Use pythonic stuff like @decorators and enjoy functions as first class objects.
Finally, try to avoid using an IDE. This keeps your files and folders structures simple and organized out of necessity. In Java it's almost impossible, but it's very possible in python as it removes so much verbosity.
A good IDE will keep that structure simple and organized, too. The problem with python is more that its dynamic, duck typing type system hinders some of the great benefits that "modern" (as in, from the past ~2 decades) IDEs bring. Since the IDE can hardly infer any type, and since even the ones it could infer can dynamically change in shape at any time, the IDE cannot provide as helpful suggestions and as powerful navigation as IDEs for other languages can.
For the same reason, compile time almost exclusively tells you about crass syntax errors only, which further diminishes an IDE's helpfulness.
I'd be curious to know if there are python IDEs who integrate with mypy (or the underlying static typing PEP) to bring some of the lost magic back to python IDEs.
Even then I'd rather avoid cumbersome navigation and typing (the fingers on keyboard kind this time, not the type system kind), as well as catching a lot of problems only in the compile step (if existing) in the best case, or at runtime in the worst case (common in python without static typing extensions).
[1] Or, I guess, projects with a small team, where all members are familiar with all or most of the code base.
Most project is somewhere in between but from what I've seen it tends towards the latter. As there are overwhelming amount of people utilizing the ease of IDE and do not care at all about the structure, or maintenance of the structure of a package.
Unless you want to mindlessly click through directory structures and files hunting for vague hints, what are you going to do? Full text search? Unless you're both careful and lucky, you will find a lot or all of the call sites as well. Which, again, gets worse the larger the project (and thus the number of call sites) gets.
Then, you better remember the arguments' type, order, and significance of the many functions you call, otherwise it's back to the navigation I've described above every time you want to use it.
This was one of the more extreme examples, but the whole problem starts to rear its ugly head pretty early in much smaller projects. The issue is however somewhat masked if you are the only or one of very few developers with high familiarity of the project. Of course then you know which file to click on and where to scroll to.
But then, even on a small project, that project rarely exists in a vacuum (the OS kernel example above is actually almost somewhat of an exception). You will use other frameworks and libraries, at the very least the language's standard library, usually, which is effectively a big project again.
Actually yes, I often have a grep tab open on the next terminal tab (whereas vim lives in the other one). Granted, I don't use it nearly as often as one would CTRL-B in intellij. grep (and other GNU utilities) is very powerful and can be used for more than just text searches. In fact for even project I develop using intellij I often find myself doing the same grep window in remote just because it's faster and I can make manual edits on the fly.
For navigation, I usually to tabe or vert sb and this allow the other call signature to simply exist on my desktop real estate or a gt away until I don't need it anymore.
You might feel like I'm simply proving your point, and you might just be right. But I do use the same method of editing on larger project outside of personal space, and delivers at speed if not just due to the fact that I need very minimal setup (the context switching is hefty when the package space is littered with various packages and not just a single one that you change all the time). I do use IDE for certain languages (yes, java), but I think it has more to deal with the verbosity and inherited complexity (chicken and egg here) then I would attribute to size alone.
The bottom line is, having been using IDE and not IDE for different projects for a long time, I would default to not using IDE if I could. It's not like I'm pathologically averse to the idea of IDE, in fact I use it daily. I just think not using the IDE has benefits both on speed for certain projects, and clarity and skill growth for others.
I've felt this pain a lot. I finally took the time to learn how to make use of the type hinting that python does offer, and now I write those type hints without even thinking about it. It makes the development experience so much better for me and across the team, since we've all bought in. It doesn't do everything. It is kind of lipstick on a pig. But it's worth doing.
I think you are spot on that people coming from weakly typed languages often don't realize what they're missing. "It clutters the code" is really just "I'm not used to seeing it that way" so if you can get people to try it out (maybe in a well-cordoned area of the code base or in some new dev) they will find out for themselves that it saves time and grief in the end.
A simple python function also is. Just much simpler. On principal, every turing complete language can do everything that you make it do, including emulating concepts that are more natural in other languages - you can write OOP in C if you want to build the whole scaffold to support it.
I also happen to know quite a number of languages, up to 10 if we talk about everything I've developed something in, but more like 5~ if we talk about ones that I'm familiar with, this includes java and python. imo programming should be language agnostic - don't try to remember the syntax, all of it is available in 10 second via googling, but remember data structures that are common across all languages and specific useful patterns and choose the right one for the job.
Both python and java have their own advantages, and own ways of doing things. But writing python like classic OOP java results in hot garbage. It defeats the purpose of using python, should just use Java if one want to emulate all of that polymorphism and OOP patterns, at least the language is built for it.
Where python falls down is the flexibility - if you aren't careful it's write only.
If you don't have a colleague, GPT-4 is an acceptable substitute.
I mean, so many people want to write production-level code and yet never took the time to actually read the production-level code right in their faces!
Even the standard library is worth seeing. Next time you import pathlib.Path, right click it, select "See Definition" and go find out how the sausage is made.
Obviously you are not expected to understand _everything_. But you will be surprised you will understand a bit. And then a bit more. And you will start getting comfortable dealing with production-level code. Soon you'll start writing it yourself.
This little habit skyrocketed my Python game
[0] - https://www.pythonmorsels.com/
Constantly circle back and refactor. Ruthlessly.
Same as in any lang, focus on data structures and algorithms (business logic is algorithmic) rather than the implementation, at least to start with. Get it working (usually easy in python, it's so dynamic!), make it good, make it fast. A good data model makes coding a joy. If your data structures suck every little thing will accrue friction. This is a red flag that you chose the wrong data model.
Source: 1000s of python hours in engineering and research roles