Python Numbers Every Programmer Should Know

(mkennedy.codes)

86 points | by WoodenChair 3 hours ago

21 comments

  • fooker 1 hour ago
    Counterintuitively: program in python only if you can get away without knowing these numbers.

    When this starts to matter, python stops being the right tool for the job.

    • libraryofbabel 1 hour ago
      Or keep your Python scaffolding, but push the performance-critical bits down into a C or Rust extension, like numpy, pandas, PyTorch and the rest all do.

      But I agree with the spirit of what you wrote - these numbers are interesting but aren’t worth memorizing. Instead, instrument your code in production to see where it’s slow in the real world with real user data (premature optimization is the root of all evil etc), profile your code (with pyspy, it’s the best tool for this if you’re looking for cpu-hogging code), and if you find yourself worrying about how long it takes to add something to a list in Python you really shouldn’t be doing that operation in Python at all.

      • eichin 51 minutes ago
        "if you're not measuring, you're not optimizing"
    • MontyCarloHall 1 hour ago
      Exactly. If you're working on an application where these numbers matter, Python is far too high-level a language to actually be able to optimize them.
  • Aurornis 53 minutes ago
    A meta-note on the title since it looks like it’s confusing a lot of commenters: The title is a play on Jeff Dean’s famous “Latency Numbers Every Programmer Should Know” from 2012. It isn’t meant to be interpreted literally. There’s a common theme in CS papers and writing to write titles that play upon themes from past papers. Another common example is the “_____ considered harmful” titles.
    • Kwpolska 20 minutes ago
      This title only works if the numbers are actually useful. Those are not, and there are far too many numbers for this to make sense.
      • Aurornis 6 minutes ago
        The title was meant to be taken literally, as in you're supposed to memorize all of these numbers. It was meant as an in-joke reference to the original writing to signal that this document was going to contain timing values for different operations.

        I completely understand why it's frustrating or confusing by itself, though.

  • willseth 1 hour ago
    Every Python programmer should be thinking about far more important things than low level performance minutiae. Great reference but practically irrelevant except in rare cases where optimization is warranted. If your workload grows to the point where this stuff actually matters, great! Until then it’s a distraction.
    • kc0bfv 53 minutes ago
      I agree - however, that has mostly been a feeling for me for years. Things feel fast enough and fine.

      This page is a nice reminder of the fact, with numbers. For a while, at least, I will Know, instead of just feel, like I can ignore the low level performance minutiae.

    • amelius 1 hour ago
      Yeah, if you hit limits just look for a module that implements the thing in C (or write it). This is how it was always done in Python.
      • willseth 55 minutes ago
        Sometimes it’s as simple as finding the hotspot with a profiler and making a simple change to an algorithm or data structure, just like you would do in any language. The amount of handwringing people do about building systems with Python is silly.
  • zelphirkalt 1 hour ago
    I doubt there is much to gain from knowing how much memory an empty string takes. The article or the listed numbers have a weird fixation on memory usage numbers and concrete time measurements. What is way more important to "every programmer" is time and space complexity, in order to avoid designing unnecessarily slow or memory hungry programs. Under the assumption of using Python, what is the use of knowing that your int takes 28 bytes? In the end you will have to determine, whether the program you wrote meats the performance criteria you have and if it does not, then you need a smarter algorithm or way of dealing with data. It helps very little to know that your 2d-array of 1000x1000 bools is so and so big. What helps is knowing, whether it is too much and maybe you should switch to using a large integer and a bitboard approach. Or switch language.
    • Qem 1 hour ago
      > Under the assumption of using Python, what is the use of knowing that your int takes 28 bytes?

      Relevant if your problem demands instatiation of a large number of objects. This reminds me of a post where Eric Raymond discusses the problems he faced while trying to use Reposurgeon to migrate GCC. See http://esr.ibiblio.org/?p=8161

  • boerseth 43 minutes ago
    That's a long list of numbers that seem oddly specific. Apart from learning that f-strings are way faster than the alternatives, and certain other comparisons, I'm not sure what I would use this for day-to-day.

    After skimming over all of them, it seems like most "simple" operations take on the order of 20ns. I will leave with that rule of thumb in mind.

    • 0x000xca0xfe 22 minutes ago
      That number isn't very useful either, it really depends on the hardware. Most virtualized server CPUs where e.g. Django will run on in the end are nowhere near the author's M4 Pro.

      Last time I benchmarked a VPS it was about the performance of an Ivy Bridge generation laptop.

  • riazrizvi 1 hour ago
    The titles are oddly worded. For example -

      Collection Access and Iteration
      How fast can you get data out of Python’s built-in collections? Here is a dramatic example of how much faster the correct data structure is. item in set or item in dict is 200x faster than item in list for just 1,000 items!
    
    It seems to suggest an iteration for x in mylist is 200x slower than for x in myset. It’s the membership test that is much slower. Not the iteration. (Also for x in mydict is an iteration over keys not values, and so isn’t what we think of as an iteration on a dict’s ‘data’).

    Also the overall title “Python Numbers Every Programmer Should Know” starts with 20 numbers that are merely interesting.

    That all said, the formatting is nice and engaging.

  • ZiiS 1 hour ago
    This is really weird thing to worry about in python. But is also misleading; Python int is arbitrary precision, they can take up much more storage and arithmetic time depending in their value.
  • mikeckennedy 34 minutes ago
    Author here.

    Thanks for the feedback everyone. I appreciate your posting it @woodenchair and @aurornis for pointing out the intent of the article.

    The idea of the article is NOT to suggest you should shave 0.5ns off by choosing some dramatically different algorithm or that you really need to optimize the heck out of everything.

    In fact, I think a lot of what the numbers show is that over thinking the optimizations often isn't worth it (e.g. caching len(coll) into a variable rather than calling it over and over is less useful that it might seem conceptually).

    Just write clean Python code. So much of it is way faster than you might have thought.

    My goal was only to create a reference to what various operations cost to have a mental model.

  • Retr0id 11 minutes ago
    > Numbers are surprisingly large in Python

    Makes me wonder if the cpython devs have ever considered v8-like NaN-boxing or pointer stuffing.

  • xnx 1 hour ago
    Python programmers don't need to know 85 different obscure performance numbers. Better to really understand ~7 general system performance numbers.
  • ktpsns 2 hours ago
    Nice numbers and it's always worth to know an order of magnitude. But these charts are far away from what "every programmer should know".
    • jerf 1 hour ago
      I think we can safely steelman the claim to "every Python programmer should know", and even from there, every "serious" Python programmer, writing Python professionally for some "important" reason, not just everyone who picks up Python for some scripting task. Obviously there's not much reason for a C# programmer to go try to memorize all these numbers.

      Though IMHO it suffices just to know that "Python is 40-50x slower than C and is bad at using multiple CPUs" is not just some sort of anti-Python propaganda from haters, but a fairly reasonable engineering estimate. If you know that you don't really need that chart. If your task can tolerate that sort of performance, you're fine; if not, figure out early how you are going to solve that problem, be it through the several ways of binding faster code to Python, using PyPy, or by not using Python in the first place, whatever is appropriate for your use case.

  • jchmbrln 1 hour ago
    What would be the explanation for an int taking 28 bytes but a list of 1000 ints taking only 7.87KB?
    • wiml 14 minutes ago
      That appears to be the size of the list itself, not including the objects it contains: 8 bytes per entry for the object pointer, and a kilo-to-kibi conversion. All Python values are "boxed", which is probably a more important thing for a Python programmer to know than most of these numbers.

      The list of floats is larger, despite also being simply an array of 1000 8-byte pointers. I assume that it's because the int array is constructed from a range(), which has a __len__(), and therefore the list is allocated to exactly the required size; but the float array is constructed from a generator expression and is presumably dynamically grown as the generator runs and has a bit of free space at the end.

  • tgv 1 hour ago
    I doubt list and string concatenation operate in constant time, or else they affect another benchmark. E.g., you can concatenate two lists in the same time, regardless of their size, but at the cost of slower access to the second one (or both).

    More contentiously: don't fret too much over performance in Python. It's a slow language (except for some external libraries, but that's not the point of the OP).

    • jerf 1 hour ago
      String concatenation is mentioned twice on that page, with the same time given. The first time it has a parenthetical "(small)", the second time doesn't have it. I expect you were looking at the second one when you typed that as I would agree that you can't just label it as a constant time, but they do seem to have meant concatenating "small" strings, where the overhead of Python's object construction would dominate the cost of the construction of the combined string.
  • mwkaufma 49 minutes ago
    Why? If those micro benchmarks mattered in your domain, you wouldn't be using python.
    • coldtea 38 minutes ago
      That's an "all or nothing" fallacy. Just because you use Python and are OK with some slowdown, doesn't mean you're OK with each and every slowdown when you can do better.

      To use a trivial example, using a set instead of a list to check membership is a very basic replacement, and can dramatically improve your running time in Python. Just because you use Python doesn't mean anything goes regarding performance.

      • mwkaufma 19 minutes ago
        That's an example of an algorithmic improvement (log n vs n), not a micro benchmark, Mr. Fallacy.
  • oogali 1 hour ago
    It's important to know that these numbers will vary based on what you're measuring, your hardware architecture, and how your particular Python binary was built.

    For example, my M4 Max running Python 3.14.2 from Homebrew (built, not poured) takes 19.73MB of RAM to launch the REPL (running `python3` at a prompt).

    The same Python version launched on the same system with a single invocation for `time.sleep()`[1] takes 11.70MB.

    My Intel Mac running Python 3.14.2 from Homebrew (poured) takes 37.22MB of RAM to launch the REPL and 9.48MB for `time.sleep`.

    My number for "how much memory it's using" comes from running `ps auxw | grep python`, taking the value of the resident set size (RSS column), and dividing by 1,024.

    1: python3 -c 'from time import sleep; sleep(100)'

  • dr_kretyn 1 hour ago
    Initially I thought how efficient strings are... but then I understood how inefficient arithmetic is. Interesting comparison but exact speed and IO depend on a lot of things, and unlikely one uses Mac mini in production so these numbers definitely aren't representative.
  • woodruffw 1 hour ago
    Great reference overall, but some of these will diverge in practice: 141 bytes for a 100 char string won’t hold for non-ASCII strings for example, and will change if/when the object header overhead changes.
  • Y_Y 1 hour ago
    int is larger than float, but list of floats is larger than list of ints

    Then again, if you're worried about any of the numbers in this article maybe you shouldn't be using Python at all. I joke, but please do at least use Numba or Numpy so you aren't paying huge overheads for making an object of every little datum.

  • ewuhic 22 minutes ago
    This is AI slop.
  • 867-5309 1 hour ago
    tfa mentions running benchmark on a multi-core platform, but doesn't mention if benchmark results used multithreading.. a brief look at the code suggests not
  • _ZeD_ 1 hour ago
    Yeah... No. I've 10+ years of python under my belt and I might have had need for this kind of micro optimizations in like 2 times most