Readit News logoReadit News
Posted by u/jfbenson a year ago
Ask HN: C/C++ developer wanting to learn efficient Python
Hey,

I have been writing python in my everyday work for the last 5 years or so. However, I never took a course on python. I want to prepare for some upcoming job interviews where I will be programming in python. How can I improve my ability to write data structure/algo code in python? I want to gain a similar understanding of what is "fast" in C++ (std::move, copy elison, etc.), but with python. Any suggested resources?

timmaxw · a year ago
In Python job interviews, I think the interviewer will only judge your code on asymptotic complexity, not absolute speed. I think Python engineers generally aren't expected to know how to micro-optimize their Python code.

Some general tips for algorithmic complexity in Python:

- Python's list is equivalent to C++ std::vector. If you need to push/pop at the head of the list, use Python's "collections.deque" to avoid the O(N) cost. Python's standard library doesn't have a linked list implementation.

- Python's dict is a fast unordered hashmap. However, if you need order-aware operations like C++'s std::map::lower_bound(), you're out of luck; Python's standard library doesn't have a tree implementation.

- Python has a "bisect" module for binary searching in a Python list, and a "heapq" module for using a Python list as a heap. However, neither one is nicely encapsulated in a data type.

If your Python program is seriously CPU-bound, the normal solution is to use a C/C++/Rust extension. For example, if you're doing large numeric calculations, use NumPy; it can store a vector of numbers as a single contiguous array, which is much faster than a list-of-Python-floats.

If you want to parallelize across CPU cores, it's important to understand the Python GIL (global interpreter lock). Often you need to use multiple Python processes. See e.g. https://superfastpython.com/multiprocessing-pool-gil/

Maybe also worth reading about __slots__ (https://wiki.python.org/moin/UsingSlots); it's a micro-optimization that helps when allocating a lot of tiny Python objects.

Hope some of that is helpful! Good luck with your job interviews.

ZeroCool2u · a year ago
"- Python's dict is a fast unordered hashmap. However, if you need order-aware operations like C++'s std::map::lower_bound(), you're out of luck; Python's standard library doesn't have a tree implementation."

I'm fairly certain that in Python 3.7 and later standard library dictionaries are now ordered by default.

alfons_foobar · a year ago
Ordered by insertion (see [Mailinglist](https://mail.python.org/pipermail/python-dev/2017-December/1...))

This might or might not be what you want/expect...

timmaxw · a year ago
Yes, Python dicts remember insertion order. This is different from C++ std::map, which maintains the keys in sorted order. For example, std::map::lower_bound(X) finds "the smallest key in the map which is greater than or equal to X" in O(log(N)) time. I don't think Python has any data structure in the standard library that supports this operation while also supporting insertion in O(log(N)) time.
az09mugen · a year ago
You're right, it's even python 3.6, and you have also the OrderedDict https://realpython.com/python-ordereddict/
DangitBobby · a year ago
A little nitpick: they were always ordered by insertion, 3.7 just codified that behavior as a guarantee instead of an implementation detail.
azundo · a year ago
I believe lower_bound is ordering by key comparison - python dicts are insertion ordered.
gwking · a year ago
I have been writing python for 15 years now and only occasionally have needed or wanted to optimize algorithms. When I have, the general takeaways have been:

* Flattening data from hierarchical, custom types into flatter, builtin collection types can make a speed difference. The builtin type methods spend more time in the native code and are optimized.

* Lots of things that I thought could make a difference but would barely move the needle. There is so much pointer indirection internal to CPython.

* The set and frozenset types can offer easy and immediate algorithmic improvements. This is obvious from a formal/academic perspective but continues to be my favorite thing about writing quick and dirty python. I have encountered cases where an algorithm called for a fancy data structure but doing simple set intersection and difference was good enough.

* Over time, Python taught me to worry less about optimizing things that didn't matter. Everyone pays lip service to the perils of premature optimization but I think there are layers to the problem. Fast languages make many affordances for optimization, and to some extent compel you to make detailed choices that have performance implications (e.g. choice of integer width, choice of collection type). There is something very liberating about reminding myself "it's going to be slow either way, and it doesn't matter." When I work in Swift for example I find myself getting distracted by finer details that relates to efficiency.

zbentley · a year ago
> There is so much pointer indirection internal to CPython.

This cannot be overstated. Really, truly, forget everything you know about cache locality when doing even basic "for-each: add numbers together"-type things in Python.

That's not an indictment; such indirection is par for the course for scripting languages, and enables a lot of features and dynamism. Additionally, the cost of that indirection may go down over time thanks to interpreter optimizations like the JIT: https://tonybaloney.github.io/posts/python-gets-a-jit.html

TheAlchemist · a year ago
I would say, there is no such thing as fast Python code. It's not the purpose of the language.

You make want to take a look at Mojo: https://www.modular.com/max/mojo

It's not really there yet, but the promise is to "combine the usability of Python with the performance of C"

cashsterling · a year ago
Numba and Cython can speed up Python code dramatically. Also, Python takes advantage of a lot of libraries which are C/C++/Rust at the their core.

In many cases, it is possible to get Python code to within 2-10x of C using numpy/numba/cython... but with 10% of the lines of code. In many cases, this is an acceptable trade.

formerly_proven · a year ago
> I would say, there is no such thing as fast Python code. It's not the purpose of the language.

It's not the purpose of the language but (business) needs don't generally care about such things. Sometimes you can't rewrite in rust for a variety of reasons and then it can pay off to know what's faster rather than slower in CPython.

rglullis · a year ago
But you can just have your python code calling a C/Rust library binding, which has been the acceptable answer for "how to make this python code faster?" since the beginning of time.
vismit2000 · a year ago
Advanced Python Mastery: https://news.ycombinator.com/item?id=36785005

Book: High Performance Python

IanOzsvald · a year ago
I'm the co-author of High Performance Python, Micha and I are working on the 3rd ed (for 2025). Lots of bits of the book came from my past conference talks, they're available here (and the public talks will generally be on youtube): https://speakerdeck.com/ianozsvald

Mostly that content has a scientific focus but the obvious thing that carries over to any part of Python is _profiling_ to figure out what's slow. Top tools I'd recommend are:

* https://pypi.org/project/scalene/ combined cpu+memory+gpu profiling

* https://github.com/gaogaotiantian/viztracer get a timeline of execution vs call-stack (great to discover what's happening deep inside pandas)

* my https://pypi.org/project/ipython-memory-usage/ if you're in Jupyter Notebooks (built on https://github.com/pythonprofilers/memory_profiler which sadly is unmaintained)

* https://github.com/pyutils/line_profiler/

randlet · a year ago
Ooh that ipython extension is nice. Thanks!
v8engine · a year ago
Check out old Pycon schedules and search for 'efficient(cy)/improve/speed/performance'.

Every Pycon has at least one talk on it and they are usually filled with a variety of tips and insights.

Prioritise by keynote speeches, recent ones, country level ones and then city Pycon.

https://pycon.org/

BerislavLopac · a year ago
Python is a very fast language, but not in the sense that you would expect as a C++ developer: its execution is (comparatively) very slow, but it shines at the speed of development.

Many things that one might take as given in other languages, in Python are optional: static type analysis, multithreading, immutability and the like. When it comes to writing algorithms in Python, it's best to think about it as executable pseudocode, here to help you get to the correct execution first and optimise for performance later.

In Python, development happens in distinct steps. The first step is to get your code to do what you need, without thinking about the readability and efficiency. In many cases, this will result in the code that is ready to be used, even in production (especially if you include unit tests and type checking, for good measure); if not, the next step is to comb the code and optimise it to be faster. What that means exactly will depend on your needs, but with a combination of external libraries like NumPy, multiprocessing and async it is quite possible to reach sufficient performance.

Finally, if none of that result in the desired speed, the performance critical components can be extracted and rewritten in a low-level language (where you have a huge advantage as a C++ dev) that the Python will happily wrap around. This is the exact strategy used by most performant libraries out there, like NumPy itself.

nick238 · a year ago
Yeah, I need to take some forget-me-nots when I have to work on the service our system's architect said had to be in Golang, and is constantly undergoing API changes because things keep getting added/changed. It currently serves ~1000 requests per day, with a goal of ~60,000 if we increase uptake across teams. Much traffic. Wow. My last job I built and maintained a group of Python microservices that handled ~500 requests/second (load balanced across ~20 containers).

I have no doubt that Golang is faster and more efficient for HTTP serving, but if you don't have a good specification for your app you're happy with for at least the next however long and need to keep moving crap around, I'd so much prefer Python.

And if I hear some flavor of "compile-time checks are tests/but Python doesn't check types" argument, that person shouldn't be involved in software development.

jdmoreira · a year ago
> And if I hear some flavor of "compile-time checks are tests/but Python doesn't check types" argument, that person shouldn't be involved in software development.

Have you ever even used a powerfull type system? I dont think so

stefanos82 · a year ago
Just read the best Python book that's out there: Fluent Python; enough said!
jfbenson · a year ago
Exactly what I was looking for. This reminds me of Straustrup's "The C++ Programming Language". Covers all of the essentials and shines the light on all of the features I didn't even know existed. THANK YOU!
b20000 · a year ago
Write your code in C++, then make a python wrapper for it. Done.
williamstein · a year ago
https://cython.org can help with that.
keithalewis · a year ago
This. Or an Excel wrapper https://gitHub.com/xlladdins/xll if you prefer a more popular language.