You would need to remove the numbers from the list as you are comparing each character to all the digits at once i.e "1" == "0123456789" , you also need to check every char before returning True:
def is_dig(s):
numbers = "0123456789" # single iterable of the numbers
for i in s:
if i not in numbers:
return False
return bool(s) # return outside the loop also catching empty string
A more efficient approach would be to use the ord and all:
def is_dig(s):
return len(s) > 0 and all(48 <= ord(ch) <= 57 for ch in s)
The ord of "0" is 48 and the ord of "9" is 57 so if the ord of the char falls in that range then you have a digit, if not all will short circuit and return False.
Using the ord without all and following your own logic would look something like:
def is_dig(s):
if not s: # empty string
return False
for ch in s:
if not 48 <= ord(ch) <= 57:
return False
return True
Answer from Padraic Cunningham on Stack Overflowcreating a function like isdigit() in python - Stack Overflow
For single-char strings, Strings' .isdigit() method is about 7% slower than simply checking ```if string in "0123456789"```. Possible bug?
How To use isdigit in python
What's the difference between str.isdigit(), isnumeric() and ...
You would need to remove the numbers from the list as you are comparing each character to all the digits at once i.e "1" == "0123456789" , you also need to check every char before returning True:
def is_dig(s):
numbers = "0123456789" # single iterable of the numbers
for i in s:
if i not in numbers:
return False
return bool(s) # return outside the loop also catching empty string
A more efficient approach would be to use the ord and all:
def is_dig(s):
return len(s) > 0 and all(48 <= ord(ch) <= 57 for ch in s)
The ord of "0" is 48 and the ord of "9" is 57 so if the ord of the char falls in that range then you have a digit, if not all will short circuit and return False.
Using the ord without all and following your own logic would look something like:
def is_dig(s):
if not s: # empty string
return False
for ch in s:
if not 48 <= ord(ch) <= 57:
return False
return True
numbers = "0123456789"
if len(str) > 0:
for i in str:
if i not in numbers:
return False
return True
Thanks Padraic and everyone for the input. @Till Hoffmann your answer was exactly what i was looking for
I was looking to optimize a program of mine that works on very, very large text files. I was fiddling around with various algorithms that perform a certain task on said data, one part of which is to convert characters to an integer;
which, of course, first has to check whether the character is an integer in the first place.
try/except was slow for my intents and purposes, so I went with the good old-fashioned if-elif-else and ran various time-measuring tests on some 2 GB of text.
My findings:
if c.isdigit(): is about 7% slower than if c in "0123456789"
This susprised me because I assumed that the algorithm behind STRING.isdigit() is essentially a for loop that goes through each character of the string to check if it's a member of "0123456789".
And since I'm trying out both time-tests on ONE-character strings only, my expectation was that the performance times would be equal.
Well... they're not, as pointed above.
Should this be considered a bug? Clearly, c.isdigit() isn't operating as efficiently as it should.
By definition, isdecimal() ⊆ isdigit() ⊆ isnumeric(). That is, if a string is decimal, then it'll also be digit and numeric.
Therefore, given a string s and test it with those three methods, there'll only be 4 types of results.
isdecimal() |
isdigit() |
isnumeric() |
Example |
|---|---|---|---|
| True | True | True | "038", "੦੩੮", "038" |
| False | True | True | "⁰³⁸", "🄀⒊⒏", "⓪③⑧" |
| False | False | True | "↉⅛⅘", "ⅠⅢⅧ", "⑩⑬㊿", "壹貳參" |
| False | False | False | "abc", "38.0", "-38" |
1. Some examples of characters isdecimal()==True
(thus isdigit()==True and isnumeric()==True)
"0123456789" DIGIT ZERO~NINE
"٠١٢٣٤٥٦٧٨٩" ARABIC-INDIC DIGIT ZERO~NINE
"०१२३४५६७८९" DEVANAGARI DIGIT ZERO~NINE
"০১২৩৪৫৬৭৮৯" BENGALI DIGIT ZERO~NINE
"੦੧੨੩੪੫੬੭੮੯" GURMUKHI DIGIT ZERO~NINE
"૦૧૨૩૪૫૬૭૮૯" GUJARATI DIGIT ZERO~NINE
"୦୧୨୩୪୫୬୭୮୯" ORIYA DIGIT ZERO~NINE
"௦௧௨௩௪௫௬௭௮௯" TAMIL DIGIT ZERO~NINE
"౦౧౨౩౪౫౬౭౮౯" TELUGU DIGIT ZERO~NINE
"೦೧೨೩೪೫೬೭೮೯" KANNADA DIGIT ZERO~NINE
"൦൧൨൩൪൫൬൭൮൯" MALAYALAM DIGIT ZERO~NINE
"๐๑๒๓๔๕๖๗๘๙" THAI DIGIT ZERO~NINE
"໐໑໒໓໔໕໖໗໘໙" LAO DIGIT ZERO~NINE
"༠༡༢༣༤༥༦༧༨༩" TIBETAN DIGIT ZERO~NINE
"၀၁၂၃၄၅၆၇၈၉" MYANMAR DIGIT ZERO~NINE
"០១២៣៤៥៦៧៨៩" KHMER DIGIT ZERO~NINE
"0123456789" FULLWIDTH DIGIT ZERO~NINE
"𝟎𝟏𝟐𝟑𝟒𝟓𝟔𝟕𝟖𝟗" MATHEMATICAL BOLD DIGIT ZERO~NINE
"𝟘𝟙𝟚𝟛𝟜𝟝𝟞𝟟𝟠𝟡" MATHEMATICAL DOUBLE-STRUCK DIGIT ZERO~NINE
"𝟢𝟣𝟤𝟥𝟦𝟧𝟨𝟩𝟪𝟫" MATHEMATICAL SANS-SERIF DIGIT ZERO~NINE
"𝟬𝟭𝟮𝟯𝟰𝟱𝟲𝟳𝟴𝟵" MATHEMATICAL SANS-SERIF BOLD DIGIT ZERO~NINE
"𝟶𝟷𝟸𝟹𝟺𝟻𝟼𝟽𝟾𝟿" MATHEMATICAL MONOSPACE DIGIT ZERO~NINE
2. Some examples of characters isdecimal()==False but isdigit()==True
(thus isnumeric()==True)
"⁰¹²³⁴⁵⁶⁷⁸⁹" SUPERSCRIPT ZERO~NINE
"₀₁₂₃₄₅₆₇₈₉" SUBSCRIPT ZERO~NINE
"🄀⒈⒉⒊⒋⒌⒍⒎⒏⒐" DIGIT ZERO~NINE FULL STOP
"🄁🄂🄃🄄🄅🄆🄇🄈🄉🄊" DIGIT ZERO~NINE COMMA
"⓪①②③④⑤⑥⑦⑧⑨" CIRCLED DIGIT ZERO~NINE
"⓿❶❷❸❹❺❻❼❽❾" NEGATIVE CIRCLED DIGIT ZERO~NINE
"⑴⑵⑶⑷⑸⑹⑺⑻⑼" PARENTHESIZED DIGIT ONE~NINE
"➀➁➂➃➄➅➆➇➈" DINGBAT CIRCLED SANS-SERIF DIGIT ONE~NINE
"⓵⓶⓷⓸⓹⓺⓻⓼⓽" DOUBLE CIRCLED DIGIT ONE~NINE
"➊➋➌➍➎➏➐➑➒" DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ONE~NINE
"፩፪፫፬፭፮፯፰፱" ETHIOPIC DIGIT ONE~NINE
3. Some examples of characters isdecimal()==False and isdigit()==False but isnumeric()==True
"½⅓¼⅕⅙⅐⅛⅑⅒⅔¾⅖⅗⅘⅚⅜⅝⅞⅟↉" VULGAR FRACTION
"৴৵৶৷৸৹" BENGALI CURRENCY NUMERATOR
"௰௱௲" TAMIL NUMBER TEN, ONE HUNDRED, ONE THOUSAND
"౸౹౺౻౼౽౾" TELUGU FRACTION DIGIT
"൰൱൲൳൴൵" MALAYALAM NUMBER, MALAYALAM FRACTION
"༳༪༫༬༭༮༯༰༱༲" TIBETAN DIGIT HALF ZERO~NINE
"፲፳፴፵፶፷፸፹፺፻፼" ETHIOPIC NUMBER TEN~NINETY, HUNDRED, TEN THOUSAND
"៰៱៲៳៴៵៶៷៸៹" KHMER SYMBOL LEK ATTAK
"ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫⅬⅭⅮⅯ" ROMAN NUMERAL
"ⅰⅱⅲⅳⅴⅵⅶⅷⅸⅹⅺⅻⅼⅽⅾⅿ" SMALL ROMAN NUMERAL
"ↀↁↂↅↆ" ROMAN NUMERAL
"⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳㉑㉒㉓㉔㉕㉖㉗㉘㉙㉚㉛㉜㉝㉞㉟㊱㊲㊳㊴㊵㊶㊷㊸㊹㊺㊻㊼㊽㊾㊿" CIRCLED NUMBER TEN~FIFTY
"㉈㉉㉊㉋㉌㉍㉎㉏" CIRCLED NUMBER TEN~EIGHTY ON BLACK SQUARE
"⑽⑾⑿⒀⒁⒂⒃⒄⒅⒆⒇" PARENTHESIZED NUMBER TEN~TWENTY
"⒑⒒⒓⒔⒕⒖⒗⒘⒙⒚⒛" NUMBER TEN~TWENTY FULL STOP
"⓫⓬⓭⓮⓯⓰⓱⓲⓳⓴" NEGATIVE CIRCLED NUMBER ELEVEN
"⓾➉❿➓" various styles of CIRCLED NUMBER TEN
"🄌" DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ZERO
"〇" IDEOGRAPHIC NUMBER ZERO
"〡〢〣〤〥〦〧〨〩〸〹〺" HANGZHOU NUMERAL ONE~TEN, TWENTY, THIRTY
"㆒㆓㆔㆕" IDEOGRAPHIC ANNOTATION ONE~FOUR MARK
"㈠㈡㈢㈣㈤㈥㈦㈧㈨㈩" PARENTHESIZED IDEOGRAPH ONE~TEN
"㊀㊁㊂㊃㊄㊅㊆㊇㊈㊉" CIRCLED IDEOGRAPH ONE~TEN
"一二三四五六七八九十壹貳參肆伍陸柒捌玖拾零百千萬億兆弐貮贰㒃㭍漆什㐅陌阡佰仟万亿幺兩㠪亖卄卅卌廾廿" CJK UNIFIED IDEOGRAPH
"參拾兩零六陸什" CJK COMPATIBILITY IDEOGRAPH
"𐄇𐄈𐄉𐄊𐄋𐄌𐄍𐄎𐄏𐄐𐄑𐄒𐄓𐄔𐄕𐄖𐄗𐄘" AEGEAN NUMBER ONE~NINE, TEN~NINETY
"𐄙𐄚𐄛𐄜𐄝𐄞𐄟𐄠𐄡𐄢𐄣𐄤𐄥𐄦𐄧𐄨𐄩𐄪" AEGEAN NUMBER ONE~NINE HUNDRED, ONE~NINE THOUSAND
"𐄬𐄭𐄮𐄯𐄰𐄱𐄲𐄳" AEGEAN NUMBER TEN~NINETY THOUSAND
"𐅀𐅁𐅂𐅃𐅆𐅇𐅈𐅉𐅊𐅋𐅌𐅍𐅎𐅏𐅐𐅑𐅒𐅓𐅔𐅕𐅖𐅗𐅘𐅙𐅚𐅛𐅜𐅝𐅞𐅟𐅠𐅡𐅢𐅣𐅤𐅥𐅦𐅧𐅨𐅩𐅪𐅫𐅬𐅭𐅮𐅯𐅰𐅱𐅲𐅳𐅴" GREEK ACROPHONIC ATTIC
"𝍠𝍡𝍢𝍣𝍤𝍥𝍦𝍧𝍨" COUNTING ROD UNIT DIGIT ONE~NINE
"𝍩𝍪𝍫𝍬𝍭𝍮𝍯𝍰𝍱" COUNTING ROD TENS DIGIT ONE~NINE
It's mostly about unicode classifications. Here's some examples to show discrepancies:
>>> def spam(s):
... for attr in 'isnumeric', 'isdecimal', 'isdigit':
... print(attr, getattr(s, attr)())
...
>>> spam('½')
isnumeric True
isdecimal False
isdigit False
>>> spam('³')
isnumeric True
isdecimal False
isdigit True
Specific behaviour is in the official docs here.
Script to find all of them:
import sys
import unicodedata
from collections import defaultdict
d = defaultdict(list)
for i in range(sys.maxunicode + 1):
s = chr(i)
t = s.isnumeric(), s.isdecimal(), s.isdigit()
if len(set(t)) == 2:
try:
name = unicodedata.name(s)
except ValueError:
name = f'codepoint{i}'
print(s, name)
d[t].append(s)
ints do not have isdigit() defined. isdigit() is a method inside of strings that checks if the string is a valid integer.
In python3 the input() function always returns a string, but if you are getting that error that means that number was somehow an int. You are using python 2.
To fix your predicament replace input() with raw_input().
Or just get python3
This might be what you're looking for, isdigit() is NOT required.
def digi():
number = input("Choose a number: ")
try:
number = int(number)
if number > 100:
print("number is greater than 100")
else:
print("number is less than or equal to 100")
except ValueError:
print("input must be 'int'")
digi()
There are differences, but they're somewhat rare*. It mainly crops up with various unicode characters, such as 2:
>>> c = '\u00B2'
>>> c.isdecimal()
False
>>> c.isdigit()
True
You can also go further down the careful-unicode-distinction rabbit hole with the isnumeric method:
>>> c = '\u00BD' # ½
>>> c.isdecimal()
False
>>> c.isdigit()
False
>>> c.isnumeric()
True
*At least, I've never encountered production code that needs to distinguish between strings that contain different types of these exceptional situations, but surely use cases exist somewhere.
Lets see some examples:
str.isdecimal() (Only Decimal Numbers)
Is 34 a decimal number? --> Yes
print("34".isdecimal()) #True
Is superscript 2 a decimal number? --> No
print("\u00B2")
print("\u00B2".isdecimal()) #False
str.isdigit() (Decimals, Subscripts, Superscripts)
Is 34 a digit? --> Yes
print("34".isdigit()) #True
Is superscript 2 a digit? --> Yes
print("\u00B2")
print("\u00B2".isdigit()) #True
str.isnumeric() (Decimals, Subscripts, Superscripts, Vulgar Fractions, Roman Numerals, Currency Numerators)
Is 34 a numeric number? --> Yes
print("34".isnumeric()) #True
Is superscript 2 a numeric number? --> Yes
print("\u00B2")
print("\u00B2".isnumeric()) #True
Is Vulgar Fraction one Quarter numeric number? -->Yes
print("\u00BC")
print("\u00BC".isnumeric()) #True