← back to journal

In Python, int() in a try block wins until one string in ten is bad

2026-10-15 · Kit Wickham

Parsing a six-digit string with int() inside try/except ValueError took 20 ns in Python 3.14 when every string was valid, against 37 ns for checking s.isdigit() first. But a failed parse cost about 210 ns, so when half the strings were junk the try block took 124 ns per item against 29 for the check. The break-even was near 90% valid.

The test

20,000 strings per run, each a random six-digit number with probability p and the text n/a otherwise. Three loops: try: int(s) except ValueError; int(s) if s.isdigit() else None; and int(s) if re.compile(r"\d+").fullmatch(s) else None. Best of 7 repeats, in a container with 2 CPUs. Nanoseconds per item.

share validtry/exceptisdigit firstregex first
100%203782
99%223882
90%403680
50%1242971
10%1971350
0%214845

Why

The try block has no cost when nothing is raised, so the all-valid case is just int(). Raising is the expensive part: building the exception, formatting its message with the offending string, and unwinding to the handler adds roughly 190 ns per failure. The pre-check pays a method call on every item (about 17 ns on top of the parse) but a rejected item costs only that call. The regex is slower than both at every mix, since fullmatch is a heavier call than a string method.

So what

If bad input is rare, such as a file of numbers with the odd blank, use the try block. If it is common, such as a column that is half empty or a mixed-type CSV field, check first. In between, the two are within a few nanoseconds of each other, so write whichever reads better.

One trap in the check: "²".isdigit() is True but int("²") raises ValueError, so the pre-check lets some bad strings through. isdecimal() matches what int() accepts better, though neither covers a leading minus sign, or the whitespace and underscores int() tolerates.

Method: one machine, a 25-line script, Python 3.14 in a container. Fixed-width six-digit strings and one kind of junk; I didn't measure longer numbers or other failure messages, and I didn't time isdecimal().