2011-12-07 11 views
12

Recentemente ho letto this question che aveva una soluzione sui loop di etichettatura in Java.Naming Loops in Python

Mi chiedo se esiste un tale sistema di denominazione del ciclo in Python. Sono stato in una situazione più volte in cui ho bisogno di uscire da un ciclo esterno for da un ciclo interno for. Di solito, risolvo questo problema inserendo il ciclo interno in una funzione che restituisce (tra gli altri) un valore booleano che viene utilizzato come condizione di rottura. Ma etichettare i loop per rompere sembra molto più semplice e mi piacerebbe provarlo, se tale funzionalità esiste in python

Qualcuno sa se lo fa?

+0

Controllare la [seconda risposta] (http://stackoverflow.com/questions/653509/breaking-out-of-nested-loops), hopefull y aiuta un po '. Ma da quello che posso vedere, nessun sistema di questo tipo esiste. –

+0

"Ma etichettare i loop per rompere sembra molto più semplice"? Più semplice delle funzioni appropriate? Come mai? Puoi fornire qualche prova di come sarebbe "più semplice"? –

+1

Non ho un esempio pratico, ma sarebbe una situazione in cui dovrei creare una funzione che verrà utilizzata solo in quel punto. Forse "più semplice" era la parola sbagliata. Quello che intendevo era che non avrei dovuto definire una nuova funzione solo per l'uso in quello spot ONE. – inspectorG4dget

risposta

9

C'è stata una proposta per includere loop denominati in python PEP3136, tuttavia, è stata respinta con una spiegazione here. Il rifiuto era dovuto principalmente al raro numero di circostanze in cui la leggibilità del codice sarebbe stata migliorata includendo questo costrutto.

1

No.

A seconda di ciò che si sta facendo, ci sono buone possibilità di utilizzare qualcosa da itertools per appiattire i loop nidificati in un ciclo for for.

8

Sebbene esistano motivi per includere il nome in loop in linguaggio costrutto, è possibile evitarlo facilmente in python senza perdita di leggibilità. Un'implementazione dell'esempio di cui in pitone

>>> try: 
    for i in xrange(0,5): 
     for j in xrange(0,6): 
      if i*j > 6: 
       print "Breaking" 
       raise StopIteration 
      print i," ",j 
except StopIteration: 
    print "Done" 


0 0 
0 1 
0 2 
0 3 
0 4 
0 5 
1 0 
1 1 
1 2 
1 3 
1 4 
1 5 
2 0 
2 1 
2 2 
2 3 
Breaking 
Done 
>>> 

I risolvere questo problema mettendo il ciclo interno in una funzione che restituisce (tra gli altri) un booleane che viene utilizzato come rottura condizione.

Penso che dovresti provare questo. Questo è molto pythonic, semplice e leggibile.

+2

+1. L'uso di eccezioni per il controllo del flusso è perfettamente cromatico in Python, sebbene sia considerato di cattivo stile in altri linguaggi, solitamente per motivi di prestazioni. – kindall

+2

Cosa succede se voglio solo "continuare" il ciclo esterno, invece di fermarlo? – Guillochon

+1

@Guillochon Basta inserire l'istruzione try all'interno del primo ciclo for – Dylanthepiguy

6

Ecco un modo per uscire di più, blocchi annidati attraverso un gestore di contesto:

import contextlib 

@contextlib.contextmanager 
def escapable(): 
    class Escape(RuntimeError): pass 
    class Unblock(object): 
     def escape(self): 
      raise Escape() 

    try: 
     yield Unblock() 
    except Escape: 
     pass 

è possibile utilizzarlo per uscire da cicli multipli:

with escapable() as a: 
    for i in xrange(30): 
     for j in xrange(30): 
      if i * j > 6: 
       a.escape() 

e si può anche nido loro:

with escapable() as a: 
    for i in xrange(30): 
     with escapable() as b: 
      for j in xrange(30): 
       if i * j == 12: 
        b.escape() # Break partway out 
       if i * j == 40: 
        a.escape() # Break all the way out