2009-08-22 20 views

Respuesta

20

Estoy de acuerdo con los demás que comienzan con es más legible, y deberías usar eso. Dicho esto, si el rendimiento es un gran problema para un caso tan especial, punto de referencia es:

$ python -m timeit -s 'text="foo"' 'text.startswith("a")' 
1000000 loops, best of 3: 0.537 usec per loop 

$ python -m timeit -s 'text="foo"' 'text[0]=="a"' 
1000000 loops, best of 3: 0.22 usec per loop 

Así es text[0] amost 2,5 veces más rápido - pero es una operación bastante rápido; ahorrarías ~ 0.3 microsegundos por comparación, dependiendo del sistema. Sin embargo, a menos que esté haciendo millones de comparaciones en una situación crítica en cuanto al tiempo, seguiría con los comienzos más legibles.

27

text[0] falla si text es una cadena vacía:

IronPython 2.6 Alpha (2.6.0.1) on .NET 4.0.20506.1 
Type "help", "copyright", "credits" or "license" for more information. 
>>> text = "" 
>>> print(text.startswith("a")) 
False 
>>> print(text[0]=='a') 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
IndexError: index out of range: 0 

EDIT: Usted dice que "sabe" que text no está vacío ... ¿cuánta confianza tiene de eso, y lo que usted quiere que suceda si es es vacío en la realidad? Si una falla es apropiada (por ejemplo, significa un error en su código) que fomentaría el uso de text[0]=='a'.

Otras preguntas:

  • ¿Cuánto le preocupa sobre el rendimiento de esto? Si esto es crítico para el rendimiento, compárelo con en su tiempo de ejecución específico de Python. No estaría por completo sorprendido al encontrar que (digamos) un formulario era más rápido en IronPython y uno diferente más rápido en CPython.

  • ¿Qué usted (y su equipo) encuentra más legible?

+0

Lo siento, no he dicho que sé que el texto no está vacío. – dugres

+4

@Jon Skeet: Es cierto, pero eso puede suceder con decir 'text [: 1]' en su lugar. – balpha

+0

@balpha: Pero esa es una pregunta diferente, entonces :) –

10

Personalmente, yo diría que startswith es más fácil de leer.

Además, a partir de Python 2.5 startwith puede tomar una tupla de prefijos para buscar:

>>> "hello world".startswith(("hello","goodbye")) 
True 
10

Sí: es más fácil de usar y fácil de leer. Cuando está tratando de detectar más de una letra, cuando se utiliza el corte en lonchas, usted tiene que saber cuánto tiempo el texto de destino es:

haystack = 'Hello, World!' 
needle = 'Hello' 

# The easy way 
result = haystack.startswith(needle) 

# The slightly harder way 
result = haystack[:len(needle)] == needle 

Editar: La pregunta parece haber cambiado. Ahora dice: "saber que el texto no está vacío y que solo nos interesa el primer carácter". Eso lo convierte en una situación hipotética bastante sin sentido.

Sospecho que el que pregunta está tratando de "optimizar" su código para la velocidad de ejecución. Si ese es el caso, mi respuesta es: no. Use la forma que sea más legible y, por lo tanto, más fácil de mantener cuando tenga que regresar y trabajar en ella dentro de un año. Optimice solo si el perfil muestra que la línea de código es el cuello de botella. Este no es un algoritmo O (n²). Es una comparación de cuerdas.

+0

La pregunta es realmente acerca de probar la primera letra. – dugres

+3

He encontrado este problema exacto en un caso de uso no hipotético; de hecho, tenía una asignación que se refería a un diccionario si solicitabas una clave que comenzaba con ~, y otro diccionario para cada otro carácter. Se llamó decenas de miles o millones de veces y, en particular, se solicitó que se volvieran a dibujar las partes sucias de una ventana cuando un mouse se movía sobre ella (una columna modelo de lista virtual GTK +), por lo que necesitaba ser extremadamente eficiente. Como no sabía que la cadena no estaba vacía, utilicé [: 1]; como se sugiere a continuación, todavía era dos veces más rápido que startsWith. –

5

La frase estándar para el questiom es: "La optimización prematura es la raíz de todo mal".

+3

Entonces, ¿cuál usarías? – dugres

+3

text.startswith ('a'). Indica claramente lo que quieres lograr. Solo puedo pensar en el texto [0] == 'a' como una alternativa, como una forma de ahorrar algunos ciclos de CPU. – Zed

+1

Presupuesto selectivo. Lea todo el párrafo en el que está incrustada esa cláusula. Ni siquiera es una oración completa en el original. – EJP

1

texto [0] == 'a' es bueno teniendo en cuenta el rendimiento. También necesita agregar validación cuando usa esto.

5

text[0] pueden fallar pero el equivalente text[:1] es seguro si la cadena está vacía.

Si quiere comparar más de un carácter, creo que .startswith() es mejor.

7

PEP 8 dice explícitamente para utilizar startswith, debido a la legibilidad:

- Use ''.startswith() and ''.endswith() instead of string 

rebanar para comprobar de prefijos o sufijos.

startswith() and endswith() are cleaner and less error prone. For 
    example: 

    Yes: if foo.startswith('bar'): 

    No: if foo[:3] == 'bar': 
2
def compo2(): 
    n = "abba" 
    for i in range(1000000): 
     n[:1]=="_" 

es más rápido que

def compo(): 
    n = "abba" 
    for i in range(1000000): 
     n.startswith("_") 

cprofile reporta 0,061 para compo2 en comparación con 0.954 para compo en mi máquina. Esto es de interés en caso de que quiera hacer MUCHAS comprobaciones de prefijo para varias "_mystring". Si la mayoría de las cadenas no comienzan con guiones bajos, entonces usando string[:1]== char antes de usar startswith es una opción para optimizar su código. En una aplicación real, este método me ahorró aproximadamente el 15% del tiempo de la CPU.

Cuestiones relacionadas