Es probable que muchos programadores de Python ignoren que la sintaxis de los while
bucles y for
bucles incluye una else:
cláusula opcional :
for val in iterable:
do_something(val)
else:
clean_up()
El cuerpo de la else
cláusula es un buen lugar para ciertos tipos de acciones de limpieza, y se ejecuta en la terminación normal del bucle: es decir, al salir del bucle return
u break
omitir la else
cláusula; saliendo después de que un lo continue
ejecuta. Sé esto solo porque lo busqué (una vez más), porque nunca puedo recordar cuándoelse
se ejecuta la cláusula.
¿Siempre? En "falla" del bucle, como su nombre indica? En la terminación regular? ¿Incluso si se sale del bucle con return
? Nunca puedo estar completamente seguro sin buscarlo.
Culpo mi persistente incertidumbre a la elección de la palabra clave: encuentro else
increíblemente poco nemónica para esta semántica. Mi pregunta no es "por qué se usa esta palabra clave para este propósito" (que probablemente votaría para cerrar, aunque solo después de leer las respuestas y comentarios), sino cómo puedo pensar en la else
palabra clave para que su semántica tenga sentido, y yo por lo tanto puede recordarlo?
Estoy seguro de que hubo una buena cantidad de discusión sobre esto, y puedo imaginar que la elección se hizo por coherencia con la cláusula de la try
declaración else:
(que también tengo que buscar), y con el objetivo de no agregar a la lista de Las palabras reservadas de Python. Quizás las razones para elegir else
aclararán su función y la harán más memorable, pero busco conectar el nombre con la función, no después de una explicación histórica per se.
Las respuestas a esta pregunta , que mi pregunta se cerró brevemente como un duplicado, contienen muchas historias interesantes. Mi pregunta tiene un enfoque diferente (cómo conectar la semántica específica de else
con la elección de la palabra clave), pero creo que debería haber un enlace a esta pregunta en alguna parte.
fuente
else
medios, básicamente, "si la condición de continuidad falla". En un bucle for tradicional, la condición de continuación es típicamentei < 42
, en cuyo caso, puede ver esa parte comoif i < 42; execute the loop body; else; do that other thing
break
. El caso de uso canónico es cuando el bucle busca algo y se rompe cuando lo encuentra. Elelse
se ejecuta solo si no se encuentra nada.Respuestas:
(Esto está inspirado en la respuesta de @Mark Tolonen).
Una
if
declaración ejecuta suelse
cláusula si su condición se evalúa como falsa. De manera idéntica, unwhile
bucle ejecuta la cláusula else si su condición se evalúa como falsa.Esta regla coincide con el comportamiento que describió:
break
instrucción, sale del bucle sin evaluar la condición, por lo que la condición no puede evaluar como falsa y nunca ejecuta la cláusula else.continue
declaración, evalúa la condición nuevamente y hace exactamente lo que normalmente haría al comienzo de una iteración de bucle. Por lo tanto, si la condición es verdadera, sigue en bucle, pero si es falsa, ejecuta la cláusula else.return
, no evalúan la condición y, por lo tanto, no ejecutan la cláusula else.for
los bucles se comportan de la misma manera. Simplemente considere la condición como verdadera si el iterador tiene más elementos, o falso en caso contrario.fuente
elif
declaraciones. Hay una respuesta que sí, y tiene un voto a favor neto.break
, en cuyo casoelse
no funcionaría pero la condición es False. Del mismo modo confor
bucles puedebreak
en el último elemento.Es mejor pensarlo de esta manera: el
else
bloque siempre se ejecutará si todo va bien en elfor
bloque anterior de modo que llegue al agotamiento.Justo en este contexto significará no
exception
, nobreak
, noreturn
. Cualquier declaración que secuestre el controlfor
provocará que se omita elelse
bloqueo.Se encuentra un caso de uso común cuando se busca un elemento en un
iterable
, para el cual la búsqueda se cancela cuando se encuentra el elemento o"not found"
se levanta / imprime una bandera a través del siguienteelse
bloque:A
continue
hace control no secuestro defor
, por lo que el control procederá a laelse
después de lafor
se agota.fuente
else
que se ejecute una cláusula cuando las cosas no salen bien, ¿no? Ya me estoy confundiendo de nuevo ...else
]", ya queelse
se ejecuta cuando ninguna de las condiciones en el ciclo for se evalúa como Verdadero, como lo demuestro en mi respuestaFalse
. Entonces, la pregunta de cómofor
se rompe depende del caso de uso.else
python). Usted proporciona un buen resumen intuitivo de lo queelse
hace, @Moses, pero no de cómo podríamos asociar este comportamiento con "else". Si se utilizara una palabra clave diferente (por ejemplo,nobreak
como se menciona en esta respuesta a una pregunta relacionada), sería más fácil entenderlo.if
/while
se evalúa como falsa o nofor
tiene elementos.break
existe el bucle contenedor (después delelse
).continue
retrocede y evalúa la condición del bucle nuevamente.¿Cuándo
if
ejecuta unelse
? Cuando su condición es falsa. Es exactamente lo mismo para elwhile
/else
. Por lo tanto, puede pensar enwhile
/else
como solo unif
que sigue ejecutando su verdadera condición hasta que evalúe falso. Abreak
no cambia eso. Simplemente salta del bucle contenedor sin evaluación. Elelse
solo se ejecuta si la evaluación de la condiciónif
/while
es falsa.El
for
es similar, excepto que su condición falsa está agotando su iterador.continue
ybreak
no se ejecutanelse
. Esa no es su función. Elbreak
sale del bucle que contiene. Lacontinue
va de nuevo a la parte superior del bucle que contiene, en donde se evalúa la condición de bucle. Es el acto de evaluarif
/while
a falso (ofor
no tiene más elementos) que se ejecutaelse
y no de otra manera.fuente
else
cláusula se ejecuta si se sale del buclecontinue
(o normalmente), pero no si salimos conbreak
. Estas sutilezas son la razón por la que estoy tratando de asimilar lo queelse
atrapa y lo que no.Esto es lo que esencialmente significa:
Es una mejor manera de escribir este patrón común:
La
else
cláusula no se ejecutará si hay unreturn
porquereturn
deja la función, como debe ser. La única excepción a lo que puede estar pensando esfinally
, cuyo propósito es asegurarse de que siempre se ejecute.continue
no tiene nada especial que ver con este asunto. Hace que la iteración actual del ciclo finalice, lo que puede suceder que finalice todo el ciclo, y claramente en ese caso el ciclo no terminó con abreak
.try/else
es similar:fuente
Si piensa en sus bucles como una estructura similar a esta (algo pseudocódigo):
podría tener un poco más de sentido. Un bucle es esencialmente solo una
if
declaración que se repite hasta que la condición esfalse
. Y este es el punto importante. El ciclo verifica su condición y ve que esfalse
así, por lo tanto ejecuta elelse
(al igual que lo normalif/else
) y luego el ciclo termina.Observe que
else
solo se ejecuta cuando se verifica la condición . Eso significa que si sale del cuerpo del bucle en medio de la ejecución con, por ejemplo, areturn
o abreak
, dado que la condición no se vuelve a comprobar, elelse
caso no se ejecutará.A,
continue
por otro lado, detiene la ejecución actual y luego salta hacia atrás para verificar la condición del bucle nuevamente, por lo que seelse
puede alcanzar en este escenario.fuente
end
etiqueta y solo coloca elgoto loop
interior delif
cuerpo. Tal vez incluso sangrienta al poner elif
en la misma línea que la etiqueta, y de repente se parece mucho a la original.Mi momento de sorpresa con la
else
cláusula del bucle fue cuando estaba viendo una charla de Raymond Hettinger , quien contó una historia sobre cómo pensó que debería haberse llamadonobreak
. Eche un vistazo al siguiente código, ¿qué cree que haría?¿Qué adivinarías que hace? Bueno, la parte que dice
nobreak
solo se ejecutará sibreak
no se golpea una declaración en el bucle.fuente
Por lo general, tiendo a pensar en una estructura de bucle como esta:
Para parecerse mucho a un número variable de
if/elif
declaraciones:En este caso, la
else
declaración en el bucle for funciona exactamente igual que laelse
declaración en la cadena deelif
s, solo se ejecuta si ninguna de las condiciones antes de evaluar a True. (o interrumpir la ejecución conreturn
o una excepción) Si mi bucle no se ajusta a esta especificación, generalmente elijo dejar de usarlofor: else
por la razón exacta por la que publicó esta pregunta: no es intuitivo.fuente
Otros ya han explicado la mecánica de
while/for...else
, y la referencia del lenguaje Python 3 tiene la definición autorizada (ver while y for ), pero aquí está mi mnemónica personal, FWIW. Supongo que la clave para mí ha sido dividir esto en dos partes: una para comprender el significado de laelse
relación con el bucle condicional y otra para comprender el control del bucle.Creo que es más fácil comenzar por comprender
while...else
:La
for...else
mnemónica es básicamente la misma:En ambos casos, el
else
parte solo se alcanza una vez que no hay más elementos para procesar, y el último elemento se ha procesado de manera regular (es decir, nobreak
oreturn
). Acontinue
simplemente regresa y ve si hay más elementos. Mi mnemotécnico para estas reglas se aplica a amboswhile
yfor
:- con "loop back to start" que significa, obviamente, el inicio del ciclo donde verificamos si hay más elementos en el iterable, en lo que respecta al
else
respecta,continue
realmente no juega ningún papel en absoluto.fuente
else
podría usarse para hacer algo cuando simplemente haya terminado con todos los elementos. Los ejemplos incluyen escribir una entrada de registro, actualizar una interfaz de usuario o indicar algún otro proceso que haya realizado. Cualquier cosa en realidad. Además, algunos fragmentos de código tienen el caso "exitoso" que terminabreak
dentro del bucle yelse
se usa para manejar el caso de "error" en el que no encontró ningún elemento adecuado durante la iteración (tal vez eso era lo que estaba pensando ¿de?).else
bloque del bucle , o realizar un seguimiento del resultado utilizando otros medios. Básicamente estoy de acuerdo, solo digo que no sé cómo las personas usan esta función y, por lo tanto, me gustaría evitar hacer suposiciones de si elelse
escenario " maneja el caso exitoso" o el escenario "else
maneja el caso fracasado" es más común. Pero tienes un buen punto, ¡así que comenta tu voto!En el desarrollo basado en pruebas (TDD), cuando se utiliza la premisa de prioridad de transformación paradigma , los bucles se tratan como una generalización de declaraciones condicionales.
Este enfoque combina bien con esta sintaxis, si considera solo declaraciones simples
if/else
(noelif
):generaliza a:
bien.
En otros idiomas, los pasos de TDD de un solo caso a casos con colecciones requieren más refactorización.
Aquí hay un ejemplo del blog 8thlight :
En el artículo vinculado en 8thlight blog, se considera el kata de Word Wrap: agregar saltos de línea a las cadenas (la
s
variable en los fragmentos a continuación) para que se ajusten a un ancho determinado (lalength
variable en los fragmentos a continuación). En un punto, la implementación tiene el siguiente aspecto (Java):y la próxima prueba, que actualmente falla es:
Entonces tenemos un código que funciona condicionalmente: cuando se cumple una condición particular, se agrega un salto de línea. Queremos mejorar el código para manejar múltiples saltos de línea. La solución presentada en el artículo propone aplicar la transformación (if-> while) , sin embargo, el autor hace un comentario que:
lo que obliga a hacer más cambios en el código en el contexto de una prueba fallida:
En TDD queremos escribir la menor cantidad de código posible para que las pruebas pasen. Gracias a la sintaxis de Python, es posible la siguiente transformación:
de:
a:
fuente
A mi modo de ver, se
else:
dispara cuando iteras más allá del final del ciclo.Si usted
break
oreturn
oraise
no lo hace iterate allá del final del bucle, se deja de Golden Retriever, y por lo tanto elelse:
no se quedará bloque. Sicontinue
todavía itera más allá del final del ciclo, ya que continuar simplemente salta a la siguiente iteración. No detiene el ciclo.fuente
goto
la parte superior del éxito). Pero es una versión más corta de la respuesta mejor votada ...Piense en la
else
cláusula como parte de la construcción del bucle;break
se separa por completo de la construcción del bucle y, por lo tanto, omiteelse
cláusula.Pero realmente, mi mapeo mental es simplemente que es la versión 'estructurada' del patrón C / C ++:
Entonces, cuando lo encuentro
for...else
o lo escribo yo mismo, en lugar de entenderlo directamente , lo traduzco mentalmente a la comprensión anterior del patrón y luego calculo qué partes del mapa de sintaxis de Python a qué partes del patrón.(Pongo 'estructurado' entre comillas de miedo porque la diferencia no es si el código está estructurado o no, sino simplemente si hay palabras clave y gramática dedicadas a la estructura particular)
fuente
else
? Si te referías a ladone:
etiqueta como proxy oelse:
, creo que la tienes exactamente al revés.done:
etiqueta. La correspondencia general es, quizás, mejor dicho así: Python tiene laelse
construcción -on-loop para que pueda expresar este patrón de flujo de control sin élgoto
.else
evita.Si empareja
else
confor
, podría ser confuso. No creo que la palabra clave hayaelse
sido una excelente opción para esta sintaxis, pero si la emparejaselse
con laif
que contienebreak
, puedes ver que realmente tiene sentido.else
es apenas útil si no hay unaif
declaración anterior y creo que es por eso que el diseñador de sintaxis eligió la palabra clave.Déjame demostrarlo en lenguaje humano.
fuente
Desde mi punto de vista, la clave es considerar el significado de
continue
más queelse
.Las otras palabras clave que menciona se rompen del bucle (salen anormalmente) mientras
continue
que no lo hace, simplemente omite el resto del bloque de código dentro del bucle. El hecho de que pueda preceder a la terminación del bucle es incidental: la terminación se realiza de la manera normal mediante la evaluación de la expresión condicional del bucle.Entonces solo necesita recordar que la
else
cláusula se ejecuta después de la terminación normal del bucle.fuente
fuente