Es probable que muchos programadores de Python ignoren que la sintaxis de los whilebucles y forbucles incluye una else:cláusula opcional :
for val in iterable:
do_something(val)
else:
clean_up()
El cuerpo de la elseclá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 returnu breakomitir la elsecláusula; saliendo después de que un lo continueejecuta. 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 elseincreí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 elsepalabra 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 trydeclaració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 elseaclarará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 elsecon la elección de la palabra clave), pero creo que debería haber un enlace a esta pregunta en alguna parte.
fuente

elsemedios, 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 thingbreak. El caso de uso canónico es cuando el bucle busca algo y se rompe cuando lo encuentra. Elelsese ejecuta solo si no se encuentra nada.Respuestas:
(Esto está inspirado en la respuesta de @Mark Tolonen).
Una
ifdeclaración ejecuta suelsecláusula si su condición se evalúa como falsa. De manera idéntica, unwhilebucle ejecuta la cláusula else si su condición se evalúa como falsa.Esta regla coincide con el comportamiento que describió:
breakinstrucció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.continuedeclaració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.forlos 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
elifdeclaraciones. Hay una respuesta que sí, y tiene un voto a favor neto.break, en cuyo casoelseno funcionaría pero la condición es False. Del mismo modo conforbucles puedebreaken el último elemento.Es mejor pensarlo de esta manera: el
elsebloque siempre se ejecutará si todo va bien en elforbloque anterior de modo que llegue al agotamiento.Justo en este contexto significará no
exception, nobreak, noreturn. Cualquier declaración que secuestre el controlforprovocará que se omita elelsebloqueo.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 siguienteelsebloque:A
continuehace control no secuestro defor, por lo que el control procederá a laelsedespués de laforse agota.fuente
elseque se ejecute una cláusula cuando las cosas no salen bien, ¿no? Ya me estoy confundiendo de nuevo ...else]", ya queelsese 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ómoforse rompe depende del caso de uso.elsepython). Usted proporciona un buen resumen intuitivo de lo queelsehace, @Moses, pero no de cómo podríamos asociar este comportamiento con "else". Si se utilizara una palabra clave diferente (por ejemplo,nobreakcomo se menciona en esta respuesta a una pregunta relacionada), sería más fácil entenderlo.if/whilese evalúa como falsa o nofortiene elementos.breakexiste el bucle contenedor (después delelse).continueretrocede y evalúa la condición del bucle nuevamente.¿Cuándo
ifejecuta unelse? Cuando su condición es falsa. Es exactamente lo mismo para elwhile/else. Por lo tanto, puede pensar enwhile/elsecomo solo unifque sigue ejecutando su verdadera condición hasta que evalúe falso. Abreakno cambia eso. Simplemente salta del bucle contenedor sin evaluación. Elelsesolo se ejecuta si la evaluación de la condiciónif/whilees falsa.El
fores similar, excepto que su condición falsa está agotando su iterador.continueybreakno se ejecutanelse. Esa no es su función. Elbreaksale del bucle que contiene. Lacontinueva 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/whilea falso (oforno tiene más elementos) que se ejecutaelsey no de otra manera.fuente
elseclá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 queelseatrapa y lo que no.Esto es lo que esencialmente significa:
Es una mejor manera de escribir este patrón común:
La
elsecláusula no se ejecutará si hay unreturnporquereturndeja 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.continueno 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/elsees 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
ifdeclaració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 esfalseasí, por lo tanto ejecuta elelse(al igual que lo normalif/else) y luego el ciclo termina.Observe que
elsesolo 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, areturno abreak, dado que la condición no se vuelve a comprobar, elelsecaso no se ejecutará.A,
continuepor otro lado, detiene la ejecución actual y luego salta hacia atrás para verificar la condición del bucle nuevamente, por lo que seelsepuede alcanzar en este escenario.fuente
endetiqueta y solo coloca elgoto loopinterior delifcuerpo. Tal vez incluso sangrienta al poner elifen la misma línea que la etiqueta, y de repente se parece mucho a la original.Mi momento de sorpresa con la
elseclá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
nobreaksolo se ejecutará sibreakno 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/elifdeclaraciones:En este caso, la
elsedeclaración en el bucle for funciona exactamente igual que laelsedeclaración en la cadena deelifs, solo se ejecuta si ninguna de las condiciones antes de evaluar a True. (o interrumpir la ejecución conreturno una excepción) Si mi bucle no se ajusta a esta especificación, generalmente elijo dejar de usarlofor: elsepor 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 laelserelació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...elsemnemónica es básicamente la misma:En ambos casos, el
elseparte 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, nobreakoreturn). Acontinuesimplemente regresa y ve si hay más elementos. Mi mnemotécnico para estas reglas se aplica a amboswhileyfor:- 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
elserespecta,continuerealmente no juega ningún papel en absoluto.fuente
elsepodrí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 terminabreakdentro del bucle yelsese 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?).elsebloque 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 elelseescenario " maneja el caso exitoso" o el escenario "elsemaneja 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
svariable en los fragmentos a continuación) para que se ajusten a un ancho determinado (lalengthvariable 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
breakoreturnoraiseno lo hace iterate allá del final del bucle, se deja de Golden Retriever, y por lo tanto elelse:no se quedará bloque. Sicontinuetodavía itera más allá del final del ciclo, ya que continuar simplemente salta a la siguiente iteración. No detiene el ciclo.fuente
gotola parte superior del éxito). Pero es una versión más corta de la respuesta mejor votada ...Piense en la
elsecláusula como parte de la construcción del bucle;breakse separa por completo de la construcción del bucle y, por lo tanto, omiteelsecláusula.Pero realmente, mi mapeo mental es simplemente que es la versión 'estructurada' del patrón C / C ++:
Entonces, cuando lo encuentro
for...elseo 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 laelseconstrucción -on-loop para que pueda expresar este patrón de flujo de control sin élgoto.elseevita.Si empareja
elseconfor, podría ser confuso. No creo que la palabra clave hayaelsesido una excelente opción para esta sintaxis, pero si la emparejaselsecon laifque contienebreak, puedes ver que realmente tiene sentido.elsees apenas útil si no hay unaifdeclaració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
continuemás queelse.Las otras palabras clave que menciona se rompen del bucle (salen anormalmente) mientras
continueque 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
elsecláusula se ejecuta después de la terminación normal del bucle.fuente
fuente