Ya sabes, he encontrado (y he probado esto una y otra vez) que try/except no funciona tan bien, por la razón que sea. Frecuentemente pruebo varias formas de hacer las cosas, y no creo haber encontrado un método que use try/except para realizar lo mejor de los examinados, de hecho, me parece que esos métodos generalmente han salido cerca del peor, si no el peor. No en todos los casos, pero en muchos casos. Sé que mucha gente dice que es la forma "Pythonic", pero esa es un área en donde me separo de ellos. Para mí, no es muy eficiente ni muy elegante, por lo tanto, tiendo a usarlo solo para detectar errores y generar informes.
Iba a quejarse de que PHP, Perl, Ruby, C e incluso el maldito caparazón tienen funciones simples para probar una cadena para enteros, pero la diligencia debida al verificar esas suposiciones me hizo tropezar. Aparentemente esta falta es una enfermedad común.
He aquí una edición rápida y sucia del puesto de Richard:
import sys, time, re
g_intRegex = re.compile(r"[-+]?\d+(\.0*)?$")
testvals = [
# integers
0, 1, -1, 1.0, -1.0,
'0', '0.','0.0', '1', '-1', '+1', '1.0', '-1.0', '+1.0', '06',
# non-integers
1.1, -1.1, '1.1', '-1.1', '+1.1',
'1.1.1', '1.1.0', '1.0.1', '1.0.0',
'1.0.', '1..0', '1..',
'0.0.', '0..0', '0..',
'one', object(), (1,2,3), [1,2,3], {'one':'two'},
# with spaces
' 0 ', ' 0.', ' .0','.01 '
]
def isInt_try(v):
try: i = int(v)
except: return False
return True
def isInt_str(v):
v = str(v).strip()
return v=='0' or (v if v.find('..') > -1 else v.lstrip('-+').rstrip('0').rstrip('.')).isdigit()
def isInt_re(v):
import re
if not hasattr(isInt_re, 'intRegex'):
isInt_re.intRegex = re.compile(r"[-+]?\d+(\.0*)?$")
return isInt_re.intRegex.match(str(v).strip()) is not None
def isInt_re2(v):
return g_intRegex.match(str(v).strip()) is not None
def timeFunc(func, times):
t1 = time.time()
for n in xrange(times):
for v in testvals:
r = func(v)
t2 = time.time()
return t2 - t1
def testFuncs(funcs):
for func in funcs:
sys.stdout.write("\t%s\t|" % func.__name__)
print
for v in testvals:
sys.stdout.write("%s" % str(v))
for func in funcs:
sys.stdout.write("\t\t%s\t|" % func(v))
print
if __name__ == '__main__':
print
print "tests.."
testFuncs((isInt_try, isInt_str, isInt_re, isInt_re2))
print
print "timings.."
print "isInt_try: %6.4f" % timeFunc(isInt_try, 10000)
print "isInt_str: %6.4f" % timeFunc(isInt_str, 10000)
print "isInt_re: %6.4f" % timeFunc(isInt_re, 10000)
print "isInt_re2: %6.4f" % timeFunc(isInt_re2, 10000)
Aquí es la parte interesante de la salida:
timings..
isInt_try: 1.2454
isInt_str: 0.7878
isInt_re: 1.5731
isInt_re2: 0.8087
Como se puede ver, el método de cadena es el más rápido. Es casi dos veces más rápido que el método de expresión regular que evita confiar en cualquier elemento global, y más de la mitad más rápido que el método try: except. El método de expresiones regulares que se basa en algunos elementos globales (o, bueno, los atributos del módulo) es un segundo cercano.
pienso en ellos, mi elección sería
isInt = isInt_str
Pero eh .. esto es copiar y nueva copia y volver a copiar toda la cadena! (¡¡Y, sin embargo, es el método más rápido !!?) Un método C podría escanearlo una vez, y listo. Un método C que escanea la secuencia una vez es lo correcto, ¿no? Supongo que podría haber algunos problemas de codificación de cadenas. De todos modos, trataría de resolver uno ahora, pero estoy fuera de tiempo para esto. = (Tal vez voy a volver a ella más tarde
Wh y ambos tratando de hacer esto "de la manera difícil?" ¿Qué pasa con try/except? –
¿qué deberían representar los valores de RepresentsInt ("17") y RepresentsInt ("+ 17")? (es decir: ¿se debe ignorar el espacio en blanco o es significativo? ¿Qué pasa con un '+'?) –
Sí, ¿qué pasa con try/except? Es mejor pedir perdón que pedir permiso. – mk12