The Python “numbers” that actually move the needle

The Python “numbers” that actually move the needle
Eyeglasses reflecting computer code on a monitor, ideal for technology and programming themes.

For Python performance, a few implementation constants matter more than micro-bench hot takes. Under the hood, CPython’s Global Interpreter Lock switches threads roughly every 5 ms (sys.getswitchinterval), so thread-based concurrency is bounded by that cadence unless C extensions release the GIL. Lists grow by about 12.5% when resized ((n >> 3) + 6), which is why append is amortized O(1) and pre-sizing large lists can reduce reallocs. Dicts and sets target a load factor around two-thirds to keep lookups fast; insertion order is preserved, but memory overhead scales with that slack. What’s notable here: integers are arbitrary precision with small-int caching from -5 to 256; beyond that, big-int ops scale with the number of 30-bit “digits” on 64-bit builds. Strings use PEP 393’s flexible storage (1/2/4 bytes per code point), so “ASCII-only” pays materially less RAM than emoji soup.

Worth noting: Python’s default recursion limit is 1000; the cyclic GC kicks in at thresholds (700, 10, 10); and ThreadPoolExecutor picks max_workers = min(32, cpu_count + 4) by default-good to know when you wonder why “more threads” plateau. The bigger picture: if you care about throughput, stay on the Python side of these constants-batch work, avoid tiny function-call granularity, and push inner loops into vectorized libraries or C-backed code. CPython 3.13’s experimental free-threaded build changes the GIL story, but the above numbers still explain most day-to-day performance behavior.

Subscribe to SmmJournal

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe