Otra cláusula en Python mientras que la declaración

321

He notado que el siguiente código es legal en Python. Mi pregunta es por qué Hay una razón específica?

n = 5
while n != 0:
    print n
    n -= 1
else:
    print "what the..."
Ivan
fuente
55
@detly: Eso es porque la mayoría de la gente evita esta construcción. :) Creo que Guido mencionó durante el proceso Py3k que, al menos, la elección de la palabra elsepara este uso había sido una muy mala idea, y que no harían más de esto.
Nicholas Knight
55
@Nicholas Knight: sí, por tentador que sea, probablemente sea algo que solo entendí a primera vista. Cualquier otra savia pobre tendría que ir a ver las especificaciones del idioma, o retroceder en el tiempo y publicar una pregunta aquí en Staeeeeey ...
detly
8
La idea detrás de elegir 'else' es que esta construcción supuestamente se usa a menudo junto con un 'if X: break' dentro del ciclo while. Dado que la cláusula 'else' se ejecuta si no salimos del bucle, forma un poco más 'else' al 'if'.
Jonathan Hartley
12
Deberían cambiarle el nombre after:.
naught101

Respuestas:

388

La elsecláusula solo se ejecuta cuando su whilecondición se vuelve falsa. Si se breaksale del ciclo o si se genera una excepción, no se ejecutará.

Una forma de pensarlo es como una construcción if / else con respecto a la condición:

if condition:
    handle_true()
else:
    handle_false()

es análogo a la construcción de bucle:

while condition:
    handle_true()
else:
    # condition is false now, handle and go on with the rest of the program
    handle_false()

Un ejemplo podría ser lo siguiente:

while value < threshold:
    if not process_acceptable_value(value):
        # something went wrong, exit the loop; don't pass go, don't collect 200
        break
    value = update(value)
else:
    # value >= threshold; pass go, collect 200
    handle_threshold_reached()
ars
fuente
42
"La cláusula else solo se ejecuta cuando su condición while se vuelve falsa". La redacción aquí implica que su estado while pasa de un estado de verdadero a falso y que lo demás se ejecutará. Sin embargo, si el while nunca es cierto, la cláusula else aún se ejecutará.
user597608
pseudocódigo Así que corrígeme si me equivoco, pero esto es exactamente lo mismo, while {} something excepto que somethingse omitirá si estás breaken el whilebucle.
Daniel Kaplan
2
Quizás el pseudocódigo más preciso sería: while (True) {if (cond) {handle_true (); } else {handle_false (); descanso; }}
VinGarcia
2
"no pases, no recojas 200", jaja, todos los que saben de dónde es esto tuvieron una buena infancia
Stefan Octavian
102

La elsecláusula se ejecuta si sale de un bloque normalmente, golpeando la condición del bucle o cayendo del fondo de un bloque try. Se no se ejecuta si breako returnfuera de un bloque, o lanzar una excepción. Funciona no solo para while y para bucles, sino también para probar bloques.

Por lo general, lo encuentra en lugares donde normalmente saldría de un bucle temprano, y salir corriendo al final del bucle es una ocasión inesperada / inusual. Por ejemplo, si está recorriendo una lista buscando un valor:

for value in values:
    if value == 5:
        print "Found it!"
        break
else:
    print "Nowhere to be found. :-("
John Kugelman
fuente
1
En realidad, una construcción bastante útil para tal cosa. No sé cuántas veces he puesto found_it=Falseal comienzo de un bucle, y luego hago un chequeo found_ital final
Cruncher
42

En respuesta a Is there a specific reason?, aquí hay una aplicación interesante: romper múltiples niveles de bucles.

Así es como funciona: el bucle externo tiene un descanso al final, por lo que solo se ejecutará una vez. Sin embargo, si el ciclo interno se completa (no encuentra divisor), entonces alcanza la instrucción else y nunca se alcanza la ruptura externa. De esta manera, una ruptura en el bucle interno saldrá de ambos bucles, en lugar de uno solo.

for k in [2, 3, 5, 7, 11, 13, 17, 25]:
    for m in range(2, 10):
        if k == m:
            continue
        print 'trying %s %% %s' % (k, m)
        if k % m == 0:
            print 'found a divisor: %d %% %d; breaking out of loop' % (k, m)
            break
    else:
        continue
    print 'breaking another level of loop'
    break
else:
    print 'no divisor could be found!'

Para ambos whiley forbucles, la elsedeclaración se ejecuta al final, a menos que breakse haya utilizado.

En la mayoría de los casos, hay mejores formas de hacerlo (envolviéndolo en una función o generando una excepción), ¡pero esto funciona!

marca
fuente
1
No voté en contra, pero creo que sé por qué alguien lo hizo. No responde la pregunta y proporciona 14 líneas de código con solo 2 líneas de descripción. Si hay una relevancia para la pregunta que se hace, no nos está diciendo ...
BlueEel
1
@BlueEel gracias por los comentarios! Agregué más explicaciones sobre el código y dejé más claro cómo responde la pregunta (porque sí responde parte de ella).
Mark
Has logrado poner tu código en contexto y, aunque no estás respondiendo todas las preguntas, veo la relevancia ahora. Voté su respuesta, ya que ahora es útil para los recién llegados y novatos (como yo en lo que respecta a Python). - Gracias, aprendí algo.
BlueEel
Me gusta la aplicación simple, ahora veo por qué alguien podría usarla. Aunque nunca he visto la necesidad de hacerlo.
gabe
El ejemplo muestra el uso de for / else pero la pregunta era específicamente sobre while / else.
Ian Goldby
20

La cláusula else se ejecuta cuando la condición while se evalúa como falsa.

De la documentación :

La instrucción while se usa para la ejecución repetida siempre que una expresión sea verdadera:

while_stmt ::=  "while" expression ":" suite
                ["else" ":" suite]

Esto prueba repetidamente la expresión y, si es verdadera, ejecuta la primera suite; si la expresión es falsa (que puede ser la primera vez que se prueba), el conjunto de la elsecláusula, si está presente, se ejecuta y el ciclo termina.

Una breakdeclaración ejecutada en el primer conjunto termina el ciclo sin ejecutar el elseconjunto de la cláusula. Una continuedeclaración ejecutada en la primera suite omite el resto de la suite y vuelve a probar la expresión.

Mark Rushakoff
fuente
15

Mi respuesta se centrará en CUÁNDO podemos usar while / for-else.

A primera vista, parece que no hay diferencia cuando se usa

while CONDITION:
    EXPRESSIONS
print 'ELSE'
print 'The next statement'

y

while CONDITION:
    EXPRESSIONS
else:
    print 'ELSE'
print 'The next statement'

Porque la print 'ELSE'declaración parece siempre ejecutada en ambos casos (ambos cuando el whileciclo finalizó o no se ejecutó).

Entonces, solo es diferente cuando la declaración print 'ELSE'no se ejecutará. Es cuando hay un breakbloque de código dentro dewhile

In [17]: i = 0

In [18]: while i < 5:
    print i
    if i == 2:
        break
    i = i +1
else:
    print 'ELSE'
print 'The next statement'
   ....:
0
1
2
The next statement

Si difiere de:

In [19]: i = 0

In [20]: while i < 5:
    print i
    if i == 2:
        break
    i = i +1
print 'ELSE'
print 'The next statement'
   ....:
0
1
2
ELSE
The next statement

return no está en esta categoría, porque tiene el mismo efecto para los dos casos anteriores.

el aumento de excepción tampoco causa diferencia, porque cuando aumenta, donde se ejecutará el siguiente código está en el controlador de excepción (excepto el bloque), el código en la elsecláusula o justo después de la whilecláusula no se ejecutará.

HVNSweeting
fuente
4

Sé que esta es una pregunta vieja pero ...

Como dijo Raymond Hettinger, debería llamarse en while/no_breaklugar de while/else.
Me resulta fácil entender y si nos fijamos en este fragmento.

n = 5
while n > 0:
    print n
    n -= 1
    if n == 2:
        break
if n == 0:
    print n

Ahora, en lugar de verificar la condición después del ciclo while, podemos intercambiarlo elsey deshacernos de esa comprobación.

n = 5
while n > 0:
    print n
    n -= 1
    if n == 2:
        break
else:  # read it as "no_break"
    print n

Siempre lo leo while/no_breakpara entender el código y esa sintaxis tiene mucho más sentido para mí.

Iluvatar
fuente
3

La cláusula else solo se ejecuta cuando la condición while se vuelve falsa.

Aquí hay unos ejemplos:

Ejemplo 1: Inicialmente, la condición es falsa, por lo que se ejecuta la cláusula else .

i = 99999999

while i < 5:
    print(i)
    i += 1
else:
    print('this')

SALIDA:

this

Ejemplo 2: El mientras condición i < 5 nunca se convirtió en falso, porque i == 3rompe el bucle, por lo demás-cláusula no se ha ejecutado.

i = 0

while i < 5:
    print(i)
    if i == 3:
        break
    i += 1
else:
    print('this')

SALIDA:

0
1
2
3

Ejemplo 3: El mientras que la condición i < 5 se convirtió en falso cuando ifue 5, por lo demás-cláusula fue ejecutado.

i = 0

while i < 5:
    print(i)
    i += 1
else:
    print('this')

SALIDA:

0
1
2
3
4
this
Saif Ur Rahman
fuente
0

La else:instrucción se ejecuta cuando y solo cuando el ciclo while ya no cumple su condición (en su ejemplo, cuando n != 0es falso).

Entonces la salida sería esta:

5
4
3
2
1
what the...
BoltClock
fuente
Lo sé, pero este tipo de while / else no funciona en Java. Me parece bastante interesante cuando descubrí que funciona en Python. Tenía curiosidad y quería saber la razón técnica.
Ivan
66
@Ivan: No es tanto que no funcione en Java, sino que no exista en Java. Podría hacerse funcionar, si alguien quisiera agregarlo al idioma.
Ignacio Vazquez-Abrams
1
No, mientras que False: .. else ... aún ejecuta la cláusula else. Es más preciso decir: de lo contrario, solo no se ejecuta si se rompe el bucle.
Leo Ufimtsev
0

El otro se ejecuta si el bucle while no se rompió.

Me gusta pensar en ello con una metáfora de "corredor".

El "más" es como cruzar la línea de meta, sin importar si comenzó al principio o al final de la pista. "else" solo no se ejecuta si se interrumpe en algún punto intermedio.

runner_at = 0 # or 10 makes no difference, if unlucky_sector is not 0-10
unlucky_sector = 6
while runner_at < 10:
    print("Runner at: ", runner_at)
    if runner_at == unlucky_sector:
        print("Runner fell and broke his foot. Will not reach finish.")
        break
    runner_at += 1
else:
    print("Runner has finished the race!") # Not executed if runner broke his foot.

Los principales casos de uso son el uso de esta ruptura de bucles anidados o si desea ejecutar algunas declaraciones solo si el bucle no se rompió en alguna parte (piense en romper como una situación inusual).

Por ejemplo, el siguiente es un mecanismo sobre cómo salir de un bucle interno sin usar variables o try / catch:

for i in [1,2,3]:
    for j in ['a', 'unlucky', 'c']:
        print(i, j)
        if j == 'unlucky':
            break
    else: 
        continue  # Only executed if inner loop didn't break.
    break         # This is only reached if inner loop 'breaked' out since continue didn't run. 

print("Finished")
# 1 a
# 1 b
# Finished
Leo Ufimtsev
fuente
-1

El mejor uso de la construcción 'while: else:' en Python debería ser si no se ejecuta ningún ciclo en 'while', entonces se ejecuta la instrucción 'else'. La forma en que funciona hoy no tiene sentido porque puede usar el siguiente código con los mismos resultados ...

n = 5
while n != 0:
    print n
    n -= 1
print "what the..."
Jean Ferri
fuente
8
No, la diferencia es que el elsebloque no se ejecutará si está dejando de usar el bucle breako la returnpalabra clave. En su ejemplo, printse ejecutará también si el ciclo ha finalizado con el breakcomando.
notsurewhattodo
2
Usted describe cómo la mayoría de las personas desean que la función funcione, ¡no cómo funciona realmente!
dotancohen
-2

Es útil para la interacción social.

while (Date != "January 1st"):
    time.sleep(1)
else:
    print("Happy new year!")
Guimoute
fuente
2
¿Y cuál es exactamente el propósito del elseaquí? El código hace exactamente lo mismo sin él.
wovano
Si su reloj y calendario breakdurante su cuenta regresiva, no usarlo elsele hará decir "¡Feliz año nuevo!" al instante, lo que no tiene ningún sentido.
Guimoute
@Guimote, ¿qué quieres decir con "si tu reloj y calendario break"? No hay breaken el código.
wovano