Регулярное выражение или другой метод синтаксического анализа строк был бы более уродливым и медленным.
Я не уверен, что что-то намного быстрее, чем указано выше. Это вызывает функцию и возвращает результат. Try / Catch не приводит к большим накладным расходам, потому что наиболее распространенное исключение перехватывается без тщательного поиска фреймов стека.
Проблема в том, что любая функция преобразования чисел имеет два вида результатов
Число, если оно допустимо
Код состояния (например, через errno) или исключение, чтобы показать, что не удалось разобрать ни одно допустимое число.
C (в качестве примера) использует несколько способов обойти это. Python излагает это четко и недвусмысленно.
Я думаю, что ваш код для этого идеален.
Ответ 3
TL; DR Лучшим решением является s.replace('.','',1).isdigit()
Я провел несколько тестов, сравнивая различные подходы
defis_number_tryexcept(s): """ Returns True if string is a number. """ try: float(s) returnTrue except ValueError: returnFalse
import re defis_number_regex(s): """ Returns True if string is a number. """ if re.match("^\d+?\.\d+?$", s) isNone: return s.isdigit() returnTrue
defis_number_repl_isdigit(s): """ Returns True if string is a number. """ return s.replace('.','',1).isdigit()
Если строка не является числом, блок except выполняется довольно медленно. Но что более важно, метод try-except - это единственный подход, который правильно обрабатывает научные обозначения.
print('Научная нотация "1.000000e+50" не поддерживается:') для f в функциях: если не f(scientific1): print('\t -', f.имя)
print('Научная нотация "1e50" не поддерживается:') для f в функциях: если не f(scientific2): print('\t -', f.name)
Научное обозначение "1.000000e + 50" не поддерживается:
is_number_regex
is_number_repl_isdigit Научная нотация "1e50" не поддерживается:
is_number_regex
is_number_repl_isdigit
РЕДАКТИРОВАТЬ: результаты теста
import timeit
test_cases = ['1.12345', '1.12.345', 'abc12345', '12345'] times_n = {f.__name__:[] for f in funcs}
for t in test_cases: for f in funcs: f = f.__name__ times_n[f].append(min(timeit.Timer('%s(t)' %f, 'from __main__ import %s, t' %f) .repeat(repeat=3, number=1000000)))
где тестировались следующие функции
from re import match as re_match from re importcompileas re_compile
defis_number_tryexcept(s): """ Returns True if string is a number. """ try: float(s) returnTrue except ValueError: returnFalse
defis_number_regex(s): """ Returns True if string is a number. """ if re_match("^\d+?\.\d+?$", s) isNone: return s.isdigit() returnTrue
comp = re_compile("^\d+?\.\d+?$")
defcompiled_regex(s): """ Returns True if string is a number. """ if comp.match(s) isNone: return s.isdigit() returnTrue
defis_number_repl_isdigit(s): """ Returns True if string is a number. """ return s.replace('.','',1).isdigit()
Ответ 4
Есть одно исключение, которое вы, возможно, захотите принять во внимание: строка 'NaN'
Если вы хотите, чтобы is_number возвращал FALSE для 'NaN', этот код не будет работать, поскольку Python преобразует его в свое представление числа, которое не является числом (поговорим о проблемах с идентификацией):
>>> float('NaN') nan
В противном случае, я должен поблагодарить вас за фрагмент кода, который я сейчас широко использую. :)