¿Hay una mejor manera de encontrar si la cadena contiene dígitos?

Estoy trabajando con cadenas que contienen tanto dígitos como caracteres alfanuméricos, o solo dígitos, pero no solo alfas. Para probar las falsas coincidencias, debo verificar si las cadenas contienen al menos un dígito, imprimiendo un mensaje de error si no lo hace. He estado usando el siguiente código:

s = '0798237 sh 523-123-asdjlh' def contains_digits(s): for char in list(s): if char.isdigit(): return True break return False if contains_digits(s) == True: print s else: print 'Error' 

¿Hay una forma más sencilla o más pythonica de hacerlo, o esto es suficiente? Además, no puedo comprobar si la cadena es alfanumérica, ya que puede contener varios símbolos (‘-‘, espacios, etc.)

Este es uno de esos lugares donde una expresión regular es la cosa:

 _digits = re.compile('\d') def contains_digits(d): return bool(_digits.search(d)) 

Pequeña demo

 >>> _digits = re.compile('\d') >>> def contains_digits(d): ... return bool(_digits.search(d)) ... >>> contains_digits('0798237 sh 523-123-asdjlh') True >>> contains_digits('sh asdjlh') False 

Puede usar el método .isdigit() con .isdigit() como se describe en la respuesta de @Wallacolloo , pero eso es más lento que la expresión regular simple:

 >>> import timeit >>> timeit.timeit("contains_digits('0798237 sh 523-123-asdjlh')", 'from __main__ import contains_digits') 0.77181887626647949 >>> timeit.timeit("contains_digits_any('0798237 sh 523-123-asdjlh')", 'from __main__ import contains_digits_any') 1.7796030044555664 

El método if está a la par con la expresión regular:

 >>> timeit.timeit("contains_digits_if('0798237 sh 523-123-asdjlh')", 'from __main__ import contains_digits_if') 0.87261390686035156 

Pero las cosas empeoran si los dígitos aparecen al final del texto:

 >>> timeit.timeit("contains_digits('asdjlhtaheoahueoaea 11 thou')", 'from __main__ import contains_digits') 1.202538013458252 >>> timeit.timeit("contains_digits_any('asdjlhtaheoahueoaea 11 thou')", 'from __main__ import contains_digits_any') 5.0348429679870605 >>> timeit.timeit("contains_digits_if('asdjlhtaheoahueoaea 11 thou')", 'from __main__ import contains_digits_if') 3.707183837890625 

Los tiempos probados en Python 2.6 en Mac OS X 10.7.

Utiliza la función any , pasando en una secuencia.
Si cualquier elemento de la secuencia es verdadero (es decir, es un dígito, en este caso), entonces any devuelve Verdadero; https://docs.python.org/library/functions.html#any

 def contains_digits(s): return any(char.isdigit() for char in s) 

Sin embargo, si te preocupa el rendimiento, tu método actual es más rápido.

Para aquellos que buscan una solución más corta: any(d in s for d in'0123456789')

Después de leer la discusión anterior, sentí curiosidad por el rendimiento de una versión basada en conjuntos como esta:

 def contains_digit(s, digits=set('0123456789')): return bool(digits.intersection(s)) 

En mis pruebas, esto fue un poco más rápido en promedio que la versión re en una computadora y un poco más lento en otra (?). Solo por diversión, comparé algunas otras versiones también.

 import math import re import timeit def contains_digit_set_intersection(s, digits=set('0123456789')): return bool(digits.intersection(s)) def contains_digit_iter_set(s, digits=set('0123456789')): for c in s: if c in digits: return True return False def contains_digit_iter_str(s, digits='0123456789'): for c in s: if c in digits: return True return False def contains_digit_re(s, digits=re.compile(r'\d')): return bool(digits.search(s)) def print_times(func, times): name = func.__name__ average = sum(times) / len(times) formatted_times = ' '.join('{:.3f}'.format(t) for t in times) message = '{name:<31} {times} ~{average:.3f}' print(message.format(name=name, times=formatted_times, average=average)) funcs = [ contains_digit_set_intersection, contains_digit_iter_set, contains_digit_iter_str, contains_digit_re, ] cases = [ '1bcdefg7', 'abcdefg7', 'abcdefgh', '0798237 sh 523-123-asdjlh', 'asdjlhtaheoahueoaea 11 thou', ] for func in funcs: times = [] for case in cases: func_case = '{func.__name__}("{case}")'.format(func=func, case=case) time = timeit.timeit(func_case, globals={func.__name__: func}) times.append(time) print_times(func, times) 

La muestra se ejecuta para las dos computadoras (el tiempo para cada caso y el ~ promedio):

 contains_digit_set_intersection 0.744 0.731 0.724 1.227 1.113 ~0.908 contains_digit_iter_set 0.264 0.541 0.566 0.260 1.068 ~0.540 contains_digit_iter_str 0.272 0.649 0.632 0.274 1.211 ~0.607 contains_digit_re 0.748 0.854 0.679 0.744 1.006 ~0.806 contains_digit_set_intersection 0.860 0.870 0.855 1.456 1.357 ~1.080 contains_digit_iter_set 0.285 0.613 0.617 0.307 1.163 ~0.597 contains_digit_iter_str 0.295 0.748 0.799 0.288 1.595 ~0.745 contains_digit_re 1.157 1.236 0.927 1.086 1.450 ~1.171