ShopperCove
Menu
All writingBlogTopicsCategoriesAboutRSS
Blog
Categories
Observability & SRE62All categories
Topics
sre111localhost lab102performance70python58javascript47bundle size36benchmarking35node.js35web development21typescript19benchmark16content creation15All topics
About
Loading article…

ShopperCove

Hands-on notes on developer tools, written after the tool has actually been run.

All writingBlogCategoriesTopicsAboutPrivacyRSS

© 2026 ShopperCove

On this page

  1. What is the difference between isdigit() and isnumeric()?
  2. What did a real test show?
  3. Why can int() fail when isdigit() is True?
  4. How do you check for negative numbers or decimals?
  5. How do you accept only ASCII 0 to 9?
  6. What does unicodedata say about these characters?
  7. FAQ
  8. Related
  9. Sources
  1. Blog

Python isdigit vs isnumeric: Which One Checks Numbers?

Both methods look like 'is this a number?' checks, but they follow Unicode rules, not int() rules. A real run on Python 3.13.5 shows where they differ.

27 October 2026·4 min read

Summary

Disclosure

This post contains affiliate links. If you buy through them, I may earn a commission at no extra cost to you. I only make firsthand claims about products I have actually used.

On this page
  1. What is the difference between isdigit() and isnumeric()?
  2. What did a real test show?
  3. Why can int() fail when isdigit() is True?
  4. How do you check for negative numbers or decimals?
  5. How do you accept only ASCII 0 to 9?
  6. What does unicodedata say about these characters?
  7. FAQ
  8. Related
  9. Sources

Python isdigit vs isnumeric: isdigit() returns True for digit characters, including superscripts like ², while isnumeric() also accepts fractions like ⅕, Roman numerals like Ⅻ and CJK numerals like 三. Neither one accepts '-5', '3.14' or ' 7'. If you want strings that int() can parse, isdecimal() is the closer match.

What is the difference between isdigit() and isnumeric()?

The Python docs define both methods through Unicode properties. str.isdigit() is True when every character has Numeric_Type Digit or Decimal and there is at least one character. str.isnumeric() is True when every character has Numeric_Type Digit, Decimal or Numeric. That extra Numeric group is where fractions, Roman numerals and many CJK numerals live. str.isdecimal() is the narrowest: it only accepts characters in the Unicode Nd category, which are the characters that can form base-10 numbers.

So every string that passes isdecimal() also passes isdigit(), and every string that passes isdigit() also passes isnumeric().

What did a real test show?

We ran this on Python 3.13.5:

tests = ['123', '٠١٢', '²', '⅕', 'Ⅻ', '三', '-5', '3.14', ' 7', '', '12']
for s in tests:
    print(repr(s), s.isdecimal(), s.isdigit(), s.isnumeric())
Stringisdecimal()isdigit()isnumeric()
'123'TrueTrueTrue
'٠١٢' (Arabic-Indic digits)TrueTrueTrue
'²' (superscript two)FalseTrueTrue
'⅕' (vulgar fraction)FalseFalseTrue
'Ⅻ' (Roman numeral twelve)FalseFalseTrue
'三' (CJK three)FalseFalseTrue
'-5'FalseFalseFalse
'3.14'FalseFalseFalse
' 7'FalseFalseFalse
'' (empty)FalseFalseFalse
'12' (full-width digits)TrueTrueTrue

The minus sign, the decimal point and the space are not digits, so all three methods reject those strings. An empty string is always False.

Why can int() fail when isdigit() is True?

int() parses base-10 digits from the Unicode Nd category, plus an optional sign and surrounding whitespace. A superscript two passes isdigit() but is not an Nd character, so int() rejects it. In our run, int('²') raised ValueError: invalid literal for int() with base 10: '²'. Meanwhile int('٠١٢') and int('12') both returned 12, because those are decimal digits in other scripts.

That is the main trap with isdigit(): it can say yes to a string that int() then refuses.

How do you check for negative numbers or decimals?

None of the three methods handles a sign, a decimal point or spaces. For real input, try the conversion and catch the error:

def to_int(s):
    try:
        return int(s)
    except ValueError:
        return None

In our run, to_int('-5') returned -5, to_int(' 7') returned 7, and to_int('3.14') and to_int('²') returned None. Use float() the same way when decimals are allowed.

How do you accept only ASCII 0 to 9?

Combine two checks: s.isascii() and s.isdigit(). In our run that returned True for '12' and False for '١٢', which is useful when a form field or ID should only contain plain ASCII digits.

What does unicodedata say about these characters?

The unicodedata module exposes the values behind these methods. unicodedata.numeric('⅕') returned 0.2 and unicodedata.digit('²') returned 2 in our run. That is a good way to see why a character passes one method and fails another.

FAQ

Which should I use to validate a number typed by a user?Usually neither. Call int() or float() inside try/except. If you only need to know whether int() will accept a string of plain digits, isdecimal() is the better match than isdigit().

Does bytes have isnumeric()?No. bytes has isdigit(), which checks ASCII 0 to 9, but it has no isnumeric() or isdecimal(). In our run b'123'.isdigit() returned True.

Is isnumeric() True for '½'?Yes. Vulgar fractions have Numeric_Type=Numeric, the same as '⅕' in the table.

Related

  • removeprefix vs lstrip in Python
  • str.translate vs replace
  • Python re vs str methods

Sources

  • 01docs.python.org/3/library/stdtypes.html
  • 02docs.python.org/3/library/functions.html
  • 03docs.python.org/3/library/unicodedata.html

Lab evidence

What I found running this

Facts checked on 26 Oct 2026 against the Python docs listed in Sources. The output table is from a real run of the snippet below on Python 3.13.5 on our Linux box, including the int() calls and the ValueError for the superscript two. We did not benchmark speed and make no performance claims here.

Explore the product

We may earn a commission

Turn Python string skills into paid client work

See how Ready Client Sites works

Notes when a lab post goes up

Occasional email for new hands-on reviews. No sequence and no sponsors.

Explore the product

We may earn a commission

Turn Python string skills into paid client work

See how Ready Client Sites works

Keep reading

  • Is typescript-eslint Strict Worth 4x Errors?

    We ran three typescript-eslint presets on a real open-source TypeScript library and counted every finding and second. The jump to strict was smaller than the jump to type-aware linting, and the findings themselves tell you whether your team is ready.

    Summary4 Nov 20267 min read

  • Python partition vs split: Which One Should You Use?

    Both cut a string at a separator, but they fail in different ways. We ran them on Python 3.13.5 to show where partition() is safer and where split() is the right tool.

    Summary2 Nov 20263 min read

  • toSorted vs sort JavaScript: Which One Copies Your Array?

    What changes when you swap sort() for toSorted(), with a real 1-million-item Node.js benchmark and the support table.

    Summary1 Nov 20263 min read