Come uscire da una clausola if


104

Che tipo di metodi esistono per uscire prematuramente da una ifclausola?

Ci sono momenti in cui sto scrivendo codice e voglio inserire breakun'istruzione all'interno di una ifclausola, solo per ricordare che quelle possono essere utilizzate solo per i cicli.

Prendiamo il seguente codice come esempio:

if some_condition:
   ...
   if condition_a:
       # do something
       # and then exit the outer if block
   ...
   if condition_b:
       # do something
       # and then exit the outer if block
   # more code here

Posso pensare a un modo per farlo: supponendo che i casi di uscita avvengano all'interno di istruzioni if ​​annidate, avvolgere il codice rimanente in un grande blocco else. Esempio:

if some_condition:
   ...
   if condition_a:
       # do something
       # and then exit the outer if block
   else:
       ...
       if condition_b:
           # do something
           # and then exit the outer if block
       else:
           # more code here

Il problema con questo è che più posizioni di uscita significano più codice di nidificazione / rientro.

In alternativa, potrei scrivere il mio codice in modo che le ifclausole siano le più piccole possibile e non richiedano alcuna uscita.

Qualcuno conosce un modo buono / migliore per uscire da una ifclausola?

Se ci sono clausole else-if e else associate, immagino che l'uscita le salterebbe.


2
Per il tuo secondo esempio di codice, lo sai elif?
Craig McQueen

2
"In alternativa, potrei scrivere il mio codice in modo che le clausole if siano le più piccole possibile e non richiedano alcuna uscita." - e sicuramente questa sarebbe la migliore linea d'azione. :-)
Michał Marczyk

2
@ Craig McQueen: Sì, ma dici che volevo che il codice fosse eseguito tra le istruzioni di condizione? Ad esempio, if a: #stuff; #stuff_inbetween; if b: #stuff;il codice intermedio dipende da not ama non dipende da b.
Roman

ciao si prega di non dimenticare elif stackoverflow.com/a/2069680/7045119
kerbrose

Risposte:


99

(Questo metodo funziona per ifs, più cicli annidati e altri costrutti da cui non puoi breakfacilmente.)

Avvolgi il codice nella sua funzione. Invece di break, usa return.

Esempio:

def some_function():
    if condition_a:
        # do something and return early
        ...
        return
    ...
    if condition_b:
        # do something else and return early
        ...
        return
    ...
    return

if outer_condition:
    ...
    some_function()
    ...

4
Sono felice di aggiungere alla tua borsa di trucchi per programmatori. Nella mia esperienza, questo approccio funziona quasi ogni volta che sei tentato di utilizzare un goto in avanti. (Ed allude e affronta situazioni in cui una singola funzione sta diventando troppo grande)
Drew Dormann

2
Idealmente puoi ottenere entrambi, ma ci sono momenti in cui devi scambiare un buon codice con buone prestazioni. Quei tempi sono rari, specialmente quando stai pensando di usare Python. In altre parole: non preoccuparti troppo del sovraccarico delle chiamate di funzione.
effimero

17
C'è un vecchio aneddoto: "Dennis Ritchie ha incoraggiato la modularità dicendo a tutti che le chiamate di funzione erano davvero, davvero economiche in C. Tutti hanno iniziato a scrivere piccole funzioni e modularizzare. Anni dopo abbiamo scoperto che le chiamate di funzione erano ancora costose sul PDP-11 e il codice VAX spesso trascorreva il 50% del suo tempo nell'istruzione CALLS. Dennis ci aveva mentito! Ma era troppo tardi; eravamo tutti agganciati ... "
effimero

1
@ephemient: è divertente, c'è dell'altro nella storia? Mi piacerebbe leggere tutto.
Roman

4
Questa citazione è dal capitolo 4 del libro The Art of Unix Programming (online su faqs.org/docs/artu ). Dovresti davvero leggere tutto, se non l'hai mai fatto prima.
effimero

55
da goto import goto, label

if some_condition:
   ...
   if condition_a:
       # fare qualcosa
       # e quindi uscire dal blocco if esterno
       goto .end
   ...
   if condition_b:
       # fare qualcosa
       # e quindi uscire dal blocco if esterno
       goto .end
   # altro codice qui

etichetta .end

(Non usarlo effettivamente, per favore.)


35
+1 perché questo è divertente. Una ricerca su Google mi ha rivelato che questo era un modulo di scherzo del pesce d'aprile.
Roman

2
Anch'io mi sono collegato. Fare clic sul primo goto.
effimero

1
questo mi ricorda il codice assembly con tutti i tipi di ramificazione :)
phunehehe

2
@ephemient: Ah, non ho notato il collegamento. Ho pensato che fosse l'evidenziazione del codice. Ma ora che guardo il tuo codice, non vedo alcuna vera evidenziazione in corso ..
Roman

1
Quando PHP ha introdotto goto, sono passato a Python php.net/manual/en/control-structures.goto.php
Marc

25
while some_condition:
   ...
   if condition_a:
       # do something
       break
   ...
   if condition_b:
       # do something
       break
   # more code here
   break

3
Oh, ehi, mi piace davvero questa idea. Penso che questo risolva esattamente il mio desiderio originale. Tuttavia, ho la fastidiosa sensazione che questa non sia una buona pratica (e per questo motivo, per ora manterrò la risposta attualmente accettata perché promuove un buon stile di codifica).
Roman

6
Nota che potresti mantenere l'originale se e avvolgere l'intera cosa in un file while True:. Assicurati solo di inserire una breakdichiarazione alla fine! Per le lingue con il costrutto do-while, è più idomatico fare:do { code that can conditionally break out } while (false);
Thomas Eding,

10

Puoi emulare la funzionalità di goto con eccezioni:

try:
    # blah, blah ...
    # raise MyFunkyException as soon as you want out
except MyFunkyException:
    pass

Dichiarazione di non responsabilità: intendo solo portare alla vostra attenzione la possibilità di fare le cose in questo modo, mentre non lo approvo in alcun modo come ragionevole in circostanze normali. Come ho accennato in un commento alla domanda, è di gran lunga preferibile strutturare il codice in modo da evitare i condizionali bizantini. :-)


Haha, mi piace questa soluzione creativa. Anche se rispetterò il tuo disclaimer e non userò un codice così originale.
Roman

@Roman: Felice di aggiungere un altro trucco accanto a quello di Shmoopty, anche quando mi sento cattivo in confronto. ;-)
Michał Marczyk

8

forse questo?

if some_condition and condition_a:
       # do something
elif some_condition and condition_b:
           # do something
           # and then exit the outer if block
elif some_condition and not condition_b:
           # more code here
else:
     #blah
if

1
Sì, potrebbe funzionare. Penso che la mia mente si sia oscurata elifmentre scrivevo questo. Anche se penso che questo non funzionerebbe in una situazione in cui voglio che il codice venga eseguito tra le istruzioni if ​​annidate.
Roman

questa è effettivamente la risposta corretta. perché non vedo che la gente lo consiglia ?? :)
kerbrose

6

Per quello che è stato effettivamente chiesto, il mio approccio è quello di inserire questi messaggi ifin un ciclo a un ciclo

while (True):
    if (some_condition):
        ...
        if (condition_a):
            # do something
            # and then exit the outer if block
            break
        ...
        if (condition_b):
            # do something
            # and then exit the outer if block
            break
        # more code here
    # make sure it is looped once
    break

Provalo:

conditions = [True,False]
some_condition = True

for condition_a in conditions:
    for condition_b in conditions:
        print("\n")
        print("with condition_a", condition_a)
        print("with condition_b", condition_b)
        while (True):
            if (some_condition):
                print("checkpoint 1")
                if (condition_a):
                    # do something
                    # and then exit the outer if block
                    print("checkpoint 2")
                    break
                print ("checkpoint 3")
                if (condition_b):
                    # do something
                    # and then exit the outer if block
                    print("checkpoint 4")
                    break
                print ("checkpoint 5")
                # more code here
            # make sure it is looped once
            break

1
Ad essere onesti, questa è la soluzione più pulita. È molto chiaro quando il codice deve uscire: non devi preoccuparti dell'ambito delle funzioni all'interno delle funzioni e non ci sono prestazioni o debiti logici.
Trento

2
Potrei considerare di usare for _ in range(1):invece di while True:. (1) Comunicare meglio la tua intenzione di un singolo ciclo di iterazione e (2) nessuna ultima dichiarazione di interruzione per uscire dal ciclo (potrebbe essere rimosso accidentalmente in seguito)
Bernhard Kausler

3

In generale, non farlo. Se annidate i "se" e vi interrompete, lo state facendo in modo sbagliato.

Tuttavia, se devi:

if condition_a:
   def condition_a_fun():
       do_stuff()
       if we_wanna_escape:
           return
   condition_a_fun()
if condition_b:
   def condition_b_fun():
       do_more_stuff()
       if we_wanna_get_out_again:
           return
   condition_b_fun()

Nota, le funzioni non DEVONO essere dichiarate nell'istruzione if, possono essere dichiarate in anticipo;) Questa sarebbe una scelta migliore, poiché eviterà di dover rifattorizzare un brutto if / then in seguito.


Grazie per la risposta. Non sono sicuro di cosa intendi per "annidamento di loop". Se ti riferisci alla mia menzione della parola chiave 'break', stavo semplicemente cercando di motivare la mia ricerca di un'uscita if confrontandola con l'esistenza di un'uscita dal loop. Inoltre, non sono sicuro di come il tuo codice risolva il problema, come il mio esempio aveva if condition_ae if condition_bnidificato all'interno di un file if some_condition. Voglio essere in grado di uscire dal if some_condition.
Roman

Il motivo per cui le persone vogliono annidare i se e romperli probabilmente non è perché lo stanno facendo male, ma forse perché vogliono scrivere codice pulito, semplice e DRY. un caso semplice è quando il programma deve fare x () quando sia condition_a che condition_b sono soddisfatte, e deve fare y () solo per condition_a, e deve fare z () solo per condition_b. e il programmatore si rifiuta di scrivere x () più volte
izzulmakin

1

In effetti, ciò che stai descrivendo sono istruzioni goto, che in genere vengono stroncate in modo piuttosto pesante. Il tuo secondo esempio è molto più facile da capire.

Tuttavia, più pulito sarebbe ancora:

if some_condition:
   ...
   if condition_a:
       your_function1()
   else:
       your_function2()

...

def your_function2():
   if condition_b:
       # do something
       # and then exit the outer if block
   else:
       # more code here

1

C'è un altro modo che non si basa sulla definizione delle funzioni (perché a volte è meno leggibile per piccoli frammenti di codice), non utilizza un ciclo while esterno aggiuntivo (che potrebbe richiedere un apprezzamento speciale nei commenti per essere comprensibile a prima vista) , non usa goto (...) e, cosa più importante, ti consente di mantenere il tuo livello di rientro per l'esterno se così non devi iniziare a nidificare le cose.

if some_condition:
   ...
   if condition_a:
       # do something
       exit_if=True # and then exit the outer if block
if some condition and not exit_if: # if and only if exit_if wasn't set we want to execute the following code
   # keep doing something
   if condition_b:
       # do something
       exit_if=True # and then exit the outer if block
if some condition and not exit_if:
   # keep doing something

Sì, questo richiede anche una seconda occhiata per la leggibilità, tuttavia, se gli snippet di codice sono piccoli non è necessario tenere traccia di alcun ciclo while che non si ripeterà mai e dopo aver capito a cosa servono i se intermedi, è facilmente leggibile, tutto in un posto e con la stessa rientranza.

E dovrebbe essere abbastanza efficiente.


0

Quindi qui capisco che stai cercando di uscire dal blocco di codice if esterno

if some_condition:
    ...
    if condition_a:
       # do something
       # and then exit the outer if block
       ...
    if condition_b:
       # do something
       # and then exit the outer if block
# more code here

Un modo per uscirne è che puoi testare una condizione falsa nel blocco if esterno, che quindi uscirà implicitamente dal blocco di codice, quindi usi un altro blocco per annidare gli altri if per fare qualcosa

if test_for_false:
    # Exit the code(which is the outer if code)

else:
    if condition_a:
        # Do something

    if condition_b:
        # Do something

0

L'unica cosa che lo applicherebbe senza metodi aggiuntivi è elifil seguente esempio

a = ['yearly', 'monthly', 'quartly', 'semiannual', 'monthly', 'quartly', 'semiannual', 'yearly']
# start the condition
if 'monthly' in b: 
    print('monthly') 
elif 'quartly' in b: 
    print('quartly') 
elif 'semiannual' in b: 
    print('semiannual') 
elif 'yearly' in b: 
    print('yearly') 
else: 
    print('final') 

-1

Ecco un altro modo per gestirlo. Utilizza un singolo elemento per il ciclo che ti consente di utilizzare solo continue. Previene l'inutile necessità di avere funzioni extra senza motivo. Inoltre, elimina i potenziali loop while infiniti.

if something:
    for _ in [0]:
        # Get x
        if not x:
            continue

        # Get y
        if not y:
            continue

        # Get z
        if not z:
            continue

        # Stuff that depends on x, y, and z

-2

l'uso returnnella condizione if ti restituirà dalla funzione, in modo che tu possa usare return per interrompere la condizione if.


2
vuole rompere se non uscire dalla funzione
StealthOne
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.