Bagaimana cara keluar dari banyak loop?

481

Diberikan kode berikut (itu tidak berfungsi):

while True:
    #snip: print out current state
    while True:
        ok = get_input("Is this ok? (y/n)")
        if ok.lower() == "y": break 2 #this doesn't work :(
        if ok.lower() == "n": break
    #do more processing with menus and stuff

Apakah ada cara untuk membuat ini berfungsi? Atau apakah saya harus melakukan satu pemeriksaan untuk keluar dari loop input, lalu yang lain, lebih terbatas, periksa di loop luar untuk memecahkan semua bersama-sama jika pengguna puas?

Matthew Scharley
sumber
87
Mengapa Python tidak hanya memiliki 'break (n)' di mana n adalah jumlah level yang ingin Anda hancurkan.
Nathan
2
C ++ bagus di sini dengan gotojika Anda berada jauh di banyak loop
Drake Johnson

Jawaban:

512

Insting pertama saya adalah untuk memperbaiki loop bersarang menjadi fungsi dan digunakan returnuntuk keluar.

Robert Rossney
sumber
3
Ini adalah pemikiran lain yang saya miliki, karena fungsi get_input_yn () akan berguna di tempat lain juga, saya yakin.
Matthew Scharley
96
setuju dalam kasus khusus ini, tetapi dalam kasus umum 'saya memiliki simpul bersarang, apa yang saya lakukan' refactoring mungkin tidak masuk akal.
quick_dry
menggunakan pengecualian mungkin lebih mudah ketika Anda harus menghasilkan daripada menggunakan kembali, namun Anda mungkin harus menggunakan itertools.islice () dalam kasus seperti itu.
robert king
5
Biasanya mungkin untuk memperbaiki loop dalam ke dalam metode sendiri, yang mengembalikan true untuk melanjutkan, false untuk memecah loop luar. sementara kondisi1: / jika tidak MyLoop2 (params): break. Alternatifnya adalah menetapkan bendera boolean, yang diuji di kedua level. lebih = Benar / sementara kondisi1 dan lebih banyak: / sementara kondisi2 dan lebih banyak: / jika stopCondition: lebih = Salah / rusak / ...
ToolmakerSteve
7
Saya setuju bahwa upaya untuk menggunakan returnadalah pendekatan yang tepat. Dan alasannya adalah bahwa, menurut Zen Python , "flat lebih baik daripada bersarang". Kami memiliki tiga tingkat sarang di sini dan jika itu mulai menghalangi, saatnya untuk mengurangi sarang atau setidaknya mengekstrak seluruh sarang ke dalam fungsinya sendiri.
Lutz Prechelt
240

Ini pendekatan lain yang pendek. Kerugiannya adalah Anda hanya dapat mematahkan loop luar, tetapi kadang-kadang itulah yang Anda inginkan.

for a in xrange(10):
    for b in xrange(20):
        if something(a, b):
            # Break the inner loop...
            break
    else:
        # Continue if the inner loop wasn't broken.
        continue
    # Inner loop was broken, break the outer.
    break

Ini menggunakan for / else construct yang dijelaskan di: Mengapa python menggunakan 'else' after for dan while loop?

Wawasan utama: Sepertinya lingkaran luar selalu putus. Tetapi jika loop dalam tidak putus, loop luar tidak akan baik.

The continuepernyataan adalah keajaiban di sini. Ada dalam klausa untuk yang lain. Menurut definisi itu terjadi jika tidak ada istirahat batin. Dalam situasi itu continuedengan rapi mengeliminasi istirahat luar.

yak
sumber
6
@eugeney Kenapa tidak? Istirahat pertama akan keluar dari lingkaran dalam.
Navin
5
@eugeney Saya merasa seperti kehilangan sesuatu di sini. Bisakah Anda memposting contoh?
Navin
4
@Mingliang yang bisa pergi sebelum melanjutkan.
Baldrickk
1
Mendapat ini dari video Raymond Hettinger, youtu.be/OSGv2VnC0go?t=971 , bacalah pernyataan "lain" yang dilampirkan pada loop sebagai "no_break", lalu menjadi lebih mudah untuk dipahami.
Ambareesh
2
Ini pintar. :-) Namun, tidak lurus ke depan. Terus terang, saya tidak yakin dengan argumen untuk tetap berlabel break atau break (n) dari Python. Penanganannya menambah kompleksitas.
rfportilla
148

PEP 3136 mengusulkan pelabelan / lanjutkan. Guido menolaknya karena "kode sangat rumit untuk memerlukan fitur ini sangat jarang". PEP memang menyebutkan beberapa solusi, (seperti teknik pengecualian), sementara Guido merasa refactoring untuk menggunakan pengembalian akan lebih sederhana dalam banyak kasus.

John Fouhy
sumber
73
Meskipun, refactor / returnbiasanya cara untuk pergi, saya telah melihat beberapa kasus di mana pernyataan ringkas ' break 2' hanya akan sangat masuk akal. Juga, refactor / returntidak berfungsi sama untuk continue. Dalam kasus ini, numeric break dan continue akan lebih mudah diikuti dan lebih sedikit berantakan daripada refactoring ke fungsi kecil, meningkatkan pengecualian, atau logika berbelit-belit yang melibatkan pengaturan bendera untuk dipecah pada setiap level sarang. Sayang sekali Guido menolaknya.
James Haigh
10
break; breakakan menyenangkan.
PyRulez
5
@ Yeekomon Masalahnya adalah Anda tidak perlu 3 atau lebih loop bersarang untuk ini menjadi masalah. 2 loop bersarang cukup umum
Jon
6
"Kode sangat rumit untuk memerlukan fitur ini sangat jarang". Tetapi jika Anda pernah menggunakan kode ini rumit, kurangnya loop berlabel akan membuatnya lebih rumit, karena Anda harus secara manual meneruskan breaksemua loop. Bodoh.
BallpointBen
3
Rupanya, saya hanya bisa mengedit posting selama 5 menit (sudah 6). Jadi, inilah postingan saya yang diedit: My 2 cents: Perl telah memberi label break (tetapi menyebutnya 'last') dan 'next' untuk melanjutkan langsung ke iterasi berikutnya. Sama sekali tidak jarang - saya menggunakannya sepanjang waktu. Saya baru untuk Python dan sudah memiliki kebutuhan untuk itu. Selain itu, penomoran bernomor akan mengerikan untuk refactoring - lebih baik memberi label loop yang ingin Anda hilangkan, kemudian gunakan break <label> untuk secara eksplisit menyatakan loop mana yang ingin Anda hilangkan.
John Deighan
119

Pertama, logika biasa sangat membantu.

Jika, karena alasan tertentu, kondisi terminasi tidak dapat dikerjakan, pengecualian adalah rencana mundur.

class GetOutOfLoop( Exception ):
    pass

try:
    done= False
    while not done:
        isok= False
        while not (done or isok):
            ok = get_input("Is this ok? (y/n)")
            if ok in ("y", "Y") or ok in ("n", "N") : 
                done= True # probably better
                raise GetOutOfLoop
        # other stuff
except GetOutOfLoop:
    pass

Untuk contoh khusus ini, pengecualian mungkin tidak diperlukan.

Di sisi lain, kita sering memiliki opsi "Y", "N" dan "Q" dalam aplikasi mode-karakter. Untuk opsi "Q", kami ingin segera keluar. Itu lebih luar biasa.

S.Lott
sumber
4
Serius, pengecualian sangat murah dan python idiomatik menggunakan banyak dan banyak dari mereka. Sangat mudah untuk mendefinisikan dan melempar yang kustom juga.
Gregg Lind
13
Ide yang menarik. Saya bingung apakah akan menyukainya atau membencinya.
Craig McQueen
8
Solusi ini akan lebih membantu, jika menunjukkan dua variasi secara terpisah. (1) menggunakan bendera ( done). (2) mengajukan pengecualian. Menggabungkan mereka menjadi satu solusi hanya membuatnya terlihat rumit. Untuk pembaca masa depan: BAIK menggunakan semua baris yang terlibat done, ATAU menentukan GetOutOfLoop(Exception)dan meningkatkan / kecuali itu.
ToolmakerSteve
4
Secara umum, menggunakan blok percobaan untuk hal lain selain pengecualian sangat disukai. Try-blok secara khusus dirancang untuk penanganan kesalahan, dan menggunakannya untuk beberapa aliran kontrol aneh tidak terlalu bagus, secara gaya.
nobillygreen
3
@ tommy.carstensen Itu omong kosong; baik mendefinisikan subkelas pengecualian baru dan menaikkannya (seperti yang ditunjukkan dalam jawaban) dan meneruskan pesan khusus ke Exceptionkonstruktor (misalnya raise Exception('bla bla bla')) valid dalam Python 2 dan Python 3. Yang pertama lebih disukai dalam kasus ini karena kami tidak ingin exceptblok kami untuk menangkap semua pengecualian, tetapi hanya pengecualian khusus yang kami gunakan untuk keluar dari loop. Jika kami melakukan hal-hal seperti yang Anda sarankan, dan kemudian bug dalam kode kami menyebabkan pengecualian yang tidak terduga muncul, itu akan diperlakukan dengan salah sama seperti sengaja keluar dari loop.
Mark Amery
54

Saya cenderung setuju bahwa refactoring ke fungsi biasanya merupakan pendekatan terbaik untuk situasi semacam ini, tetapi untuk ketika Anda benar - benar perlu keluar dari loop bersarang, inilah varian menarik dari pendekatan peningkatan pengecualian yang dijelaskan oleh @ S.Lott. Ini menggunakan withpernyataan Python untuk membuat kenaikan pengecualian terlihat sedikit lebih baik. Tetapkan manajer konteks baru (Anda hanya perlu melakukan ini satu kali) dengan:

from contextlib import contextmanager
@contextmanager
def nested_break():
    class NestedBreakException(Exception):
        pass
    try:
        yield NestedBreakException
    except NestedBreakException:
        pass

Sekarang Anda dapat menggunakan manajer konteks ini sebagai berikut:

with nested_break() as mylabel:
    while True:
        print "current state"
        while True:
            ok = raw_input("Is this ok? (y/n)")
            if ok == "y" or ok == "Y": raise mylabel
            if ok == "n" or ok == "N": break
        print "more processing"

Keuntungan: (1) ini sedikit lebih bersih (tidak ada blok coba-kecuali eksplisit), dan (2) Anda mendapatkan Exceptionsubkelas yang dibuat khusus untuk setiap penggunaan nested_break; tidak perlu mendeklarasikan Exceptionsubclass Anda sendiri setiap kali.

Mark Dickinson
sumber
40

Pertama, Anda juga dapat mempertimbangkan untuk membuat proses mendapatkan dan memvalidasi fungsi input; dalam fungsi itu, Anda bisa mengembalikan nilai jika itu benar, dan terus berputar di loop sementara jika tidak. Ini pada dasarnya meniadakan masalah yang Anda selesaikan, dan biasanya dapat diterapkan dalam kasus yang lebih umum (keluar dari banyak loop). Jika Anda benar-benar harus menjaga struktur ini dalam kode Anda, dan benar-benar tidak ingin berurusan dengan para boolean pembukuan ...

Anda juga dapat menggunakan goto dengan cara berikut (menggunakan modul April Mop dari sini ):

#import the stuff
from goto import goto, label

while True:
    #snip: print out current state
    while True:
        ok = get_input("Is this ok? (y/n)")
        if ok == "y" or ok == "Y": goto .breakall
        if ok == "n" or ok == "N": break
    #do more processing with menus and stuff
label .breakall

Saya tahu, saya tahu, "kamu tidak boleh menggunakan goto" dan semua itu, tetapi itu bekerja dengan baik dalam kasus-kasus aneh seperti ini.

Matt J
sumber
1
Jika itu seperti perintah COME FROM di INTERCAL, maka tidak ada
1800 INFORMASI
3
saya suka leluconnya, tetapi tujuan stack overflow adalah mempromosikan kode yang baik, jadi saya harus memilih Anda :(
Christian Oudard
13
Saya pikir ini solusi yang bersih dan cukup mudah dibaca untuk memenuhi syarat sebagai kode yang baik, jadi saya pilih itu. :)
JT Hurley
1
@JTHurley tidak, ini tidak bersih dan tidak dapat dibaca. Maksud saya, ini mungkin terlihat bersih dan mudah dibaca dalam contoh ini tetapi dalam skenario kehidupan nyata apapun membuat kekacauan suci . (Juga ini sangat anti-pythonic ...)
Alois Mahdal
2
goto mendapat rep yang buruk, setiap programmer profesional harus dapat menanganinya dengan benar menurut saya.
Albert Renshaw
33

Perkenalkan variabel baru yang akan Anda gunakan sebagai 'loop breaker'. Pertama tetapkan sesuatu untuk itu (Salah, 0, dll.), Dan kemudian, di dalam lingkaran luar, sebelum Anda memutuskannya, ubah nilainya menjadi sesuatu yang lain (Benar, 1, ...). Setelah loop keluar, lakukan loop 'induk' untuk memeriksa nilai itu. Biarkan saya menunjukkan:

breaker = False #our mighty loop exiter!
while True:
    while True:
        if conditionMet:
            #insert code here...
            breaker = True 
            break
    if breaker: # the interesting part!
        break   # <--- !

Jika Anda memiliki loop tak terbatas, ini adalah satu-satunya jalan keluar; untuk eksekusi loop lainnya jauh lebih cepat. Ini juga berfungsi jika Anda memiliki banyak loop bersarang. Anda dapat keluar semua, atau hanya beberapa. Kemungkinan tak terbatas! Semoga ini bisa membantu!

krvolok
sumber
22

Untuk keluar dari beberapa loop bersarang, tanpa refactoring ke fungsi, gunakan "pernyataan goto yang disimulasikan" dengan pengecualian StopIteration bawaan :

try:
    for outer in range(100):
        for inner in range(100):
            if break_early():
                raise StopIteration

except StopIteration: pass

Lihat diskusi ini tentang penggunaan pernyataan goto untuk keluar dari loop bersarang.

Justas
sumber
1
Ini terlihat jauh lebih bagus daripada membuat kelas Anda sendiri untuk menangani pengecualian, dan terlihat sangat bersih. Apakah ada alasan saya tidak boleh melakukan ini?
mgjk
Sebenarnya StopIteration digunakan untuk generator, tapi saya pikir biasanya Anda tidak memiliki pengecualian StopIteration yang belum ditonton. Jadi sepertinya ini solusi yang bagus tetapi tidak ada kesalahan dalam membuat pengecualian baru.
Kowalski
1
Solusi terbaik dan paling sederhana untuk saya
Alexandre Huat
16

keeplooping=True
while keeplooping:
    #Do Stuff
    while keeplooping:
          #do some other stuff
          if finisheddoingstuff(): keeplooping=False

atau semacam itu. Anda bisa mengatur variabel di loop dalam, dan memeriksanya di loop luar segera setelah loop dalam keluar, rusak jika perlu. Saya agak suka metode GOTO, asalkan Anda tidak keberatan menggunakan modul lelucon April Mop - ini bukan Pythonic, tapi itu masuk akal.

cepat kering
sumber
ini semacam pengaturan bendera!
SIslam
Saya pikir ini solusi yang sangat bagus.
Kowalski
13

Ini bukan cara tercantik untuk melakukannya, tetapi menurut saya, ini cara terbaik.

def loop():
    while True:
    #snip: print out current state
        while True:
            ok = get_input("Is this ok? (y/n)")
            if ok == "y" or ok == "Y": return
            if ok == "n" or ok == "N": break
        #do more processing with menus and stuff

Saya cukup yakin Anda bisa melakukan sesuatu menggunakan rekursi di sini juga, tapi saya tidak tahu apakah itu pilihan yang baik untuk Anda.

Jason Baker
sumber
Ini solusi tepat bagi saya. Kasus penggunaan saya sangat berbeda dari OP. Saya pada dasarnya mengulang data yang sama dua kali untuk menemukan permutasi, jadi saya tidak ingin memisahkan keduanya sementara loop.
Brian Peterson
9

Dan mengapa tidak terus mengulang-ulang jika dua kondisi itu benar? Saya pikir ini adalah cara yang lebih pythonic:

dejaVu = True

while dejaVu:
    while True:
        ok = raw_input("Is this ok? (y/n)")
        if ok == "y" or ok == "Y" or ok == "n" or ok == "N":
            dejaVu = False
            break

Bukan?

Semua yang terbaik.

Mauro Aspé
sumber
kenapa tidak adil while dejaVu:? Anda tetap menetapkannya menjadi benar.
Matthew Scharley
hei itu berhasil! Saya berpikir dalam dua Truekondisi untuk melewatkan dua loop, tetapi hanya satu yang cukup.
Mauro Aspé
2
@ MatthewScharley Saya pikir ini untuk menunjukkan bahwa ini berfungsi dalam loop bersarang.
tangani
@ MauroAspé ini tidak akan melakukan apa yang diminta OP. masih akan mengeksekusi seluruh loop luar tetapi targetnya adalah bahwa jika Anda memecahkan sisa kode tidak akan dieksekusi
yamm
@yamm Bisakah itu tidak diselesaikan dengan if not dejaVu: breakdi bagian bawah dan dengan demikian keluar dari loop utama? Saya pikir solusinya paling dekat dengan apa yang diminta. +1
milcak
8

Factor logika loop Anda menjadi sebuah iterator yang menghasilkan variabel loop dan kembali ketika selesai - berikut ini adalah yang sederhana yang menjabarkan gambar dalam baris / kolom sampai kita kehabisan gambar atau keluar dari tempat untuk meletakkannya:

def it(rows, cols, images):
    i = 0
    for r in xrange(rows):
        for c in xrange(cols):
            if i >= len(images):
                return
            yield r, c, images[i]
            i += 1 

for r, c, image in it(rows=4, cols=4, images=['a.jpg', 'b.jpg', 'c.jpg']):
    ... do something with r, c, image ...

Ini memiliki keuntungan memisahkan logika loop rumit dan pemrosesan ...

Matt Billenstein
sumber
3

Dalam hal ini, sebagaimana ditunjukkan oleh orang lain juga, dekomposisi fungsional adalah cara yang harus dilakukan. Kode dalam Python 3:

def user_confirms():
    while True:
        answer = input("Is this OK? (y/n) ").strip().lower()
        if answer in "yn":
            return answer == "y"

def main():
    while True:
        # do stuff
        if user_confirms():
            break
Loax
sumber
3

Ada trik tersembunyi dalam while ... elsestruktur Python yang dapat digunakan untuk mensimulasikan double break tanpa banyak perubahan / penambahan kode. Intinya jika whilekondisinya salah, elseblok dipicu. Tidak ada pengecualian, continueatau breakmemicu elseblokir. Untuk informasi lebih lanjut, lihat jawaban " Klausa lain pada pernyataan Python sementara ", atau dokumen Python sementara (v2.7) .

while True:
    #snip: print out current state
    ok = ""
    while ok != "y" and ok != "n":
        ok = get_input("Is this ok? (y/n)")
        if ok == "n" or ok == "N":
            break    # Breaks out of inner loop, skipping else

    else:
        break        # Breaks out of outer loop

    #do more processing with menus and stuff

Satu-satunya downside adalah bahwa Anda perlu memindahkan kondisi melanggar ganda ke dalam whilekondisi (atau menambahkan variabel bendera). Variasi ini ada juga untuk forloop, di mana elseblok dipicu setelah loop selesai.

holroy
sumber
Ini tampaknya tidak memenuhi persyaratan istirahat ganda. Bekerja untuk masalah yang diberikan, tetapi tidak untuk pertanyaan yang sebenarnya.
Dakkaron
@Dakkaron Anda yakin telah memahami kode dengan benar? Kode memang memecahkan pertanyaan OPs, dan istirahat mirip dengan permintaan. Namun itu tidak keluar dari beberapa loop, tetapi gunakan klausa lain untuk menggantikan kebutuhan menggandakan istirahat.
holroy
Dari pemahaman saya, pertanyaannya adalah How to break out of multiple loops in Python?dan jawabannya seharusnya adalah "Tidak berhasil, coba yang lain". Saya tahu itu memperbaiki contoh yang diberikan dari OP, tetapi tidak menjawab pertanyaan mereka.
Dakkaron
@ Dakkaron, Lihat pernyataan masalah di bawah kode, dan menurut saya itu memang menjawab pertanyaan OP.
holroy
2

Cara lain untuk mengurangi iterasi Anda menjadi satu tingkat loop akan melalui penggunaan generator seperti yang ditentukan dalam referensi python

for i, j in ((i, j) for i in A for j in B):
    print(i , j)
    if (some_condition):
        break

Anda bisa meningkatkannya ke sejumlah level untuk loop

Kelemahannya adalah Anda tidak lagi dapat menembus hanya satu level. Semuanya atau tidak sama sekali.

Kelemahan lain adalah tidak bekerja dengan loop sementara. Saya awalnya ingin memposting jawaban ini dengan Python - `break` dari semua loop tetapi sayangnya itu ditutup sebagai duplikat dari yang ini

Peeyush Kushwaha
sumber
1
Ini berfungsi untuk sementara loop juga, Anda hanya perlu menulis generator Anda sebagai def (dengan hasil), bukan sebagai pemahaman.
Veky
Ya, seorang pembicara di PyCon mengklaim bahwa bahkan jawaban yang diterima oleh RobertRossney bukanlah benar-benar Pythonic, tetapi generator adalah cara yang tepat untuk memutus banyak loop. (Saya sarankan menonton seluruh video!)
Post169
2

Alasan saya datang ke sini adalah saya memiliki loop luar dan loop dalam seperti:

for x in array:
  for y in dont_use_these_values:
    if x.value==y:
      array.remove(x)  # fixed, was array.pop(x) in my original answer
      continue

  do some other stuff with x

Seperti yang Anda lihat, itu tidak akan benar-benar pergi ke x berikutnya, tetapi akan pergi ke y berikutnya.

apa yang saya temukan untuk menyelesaikan ini adalah menjalankan array dua kali sebagai gantinya:

for x in array:
  for y in dont_use_these_values:
    if x.value==y:
      array.remove(x)  # fixed, was array.pop(x) in my original answer
      continue

for x in array:
  do some other stuff with x

Saya tahu ini adalah kasus spesifik dari pertanyaan OP, tetapi saya mempostingnya dengan harapan bahwa itu akan membantu seseorang memikirkan masalah mereka secara berbeda sambil menjaga hal-hal sederhana.

Nathan Garabedian
sumber
Ini mungkin bukan Python. Apa jenis array? Mungkin daftar, tetapi apa isinya? Bahkan jika itu berisi ints, array.pop (x) mungkin tidak akan melakukan apa yang Anda inginkan.
Veky
Itu poin yang bagus. Saya tidak dapat menemukan kode yang saya rujuk. Bagi siapa pun yang membaca ini, array.pop (i) "Menghapus item dengan indeks i dari array dan mengembalikannya." sesuai dokumentasi python. Jadi kita perlu mendapatkan indeks item x dalam array untuk membuat kode ini berfungsi seperti yang diharapkan. Ada juga fungsi array.remove (x) yang akan melakukan apa yang diharapkan. Saya akan mengubah jawaban saya di atas untuk memperbaiki kesalahan itu. Ini mengasumsikan array kedua tidak mengandung duplikat, karena array.remove (x) hanya akan menghapus instance x pertama yang ditemukan.
Nathan Garabedian
Ok, kalau begitu saya mengerti. Dalam hal itu, hanya menggunakan breakalih-alih continueakan melakukan apa yang Anda inginkan, bukan? :-)
Veky
Ya, untuk efisiensi dan kejelasan, Anda mungkin ingin menggunakan jeda daripada melanjutkan dalam contoh-contoh ini. :)
Nathan Garabedian
2

Coba gunakan generator tanpa batas.

from itertools import repeat
inputs = (get_input("Is this ok? (y/n)") for _ in repeat(None))
response = (i.lower()=="y" for i in inputs if i.lower() in ("y", "n"))

while True:
    #snip: print out current state
    if next(response):
        break
    #do more processing with menus and stuff
raja robert
sumber
2

Dengan menggunakan fungsi:

def myloop():
    for i in range(1,6,1):  # 1st loop
        print('i:',i)
        for j in range(1,11,2):  # 2nd loop
            print('   i, j:' ,i, j)
            for k in range(1,21,4):  # 3rd loop
                print('      i,j,k:', i,j,k)
                if i%3==0 and j%3==0 and k%3==0:
                    return  # getting out of all loops

myloop()

Coba jalankan kode di atas dengan berkomentar returnjuga.

Tanpa menggunakan fungsi apa pun:

done = False
for i in range(1,6,1):  # 1st loop
    print('i:', i)
    for j in range(1,11,2):  # 2nd loop
        print('   i, j:' ,i, j)
        for k in range(1,21,4):  # 3rd loop
            print('      i,j,k:', i,j,k)
            if i%3==0 and j%3==0 and k%3==0:
                done = True
                break  # breaking from 3rd loop
        if done: break # breaking from 2nd loop
    if done: break     # breaking from 1st loop

Sekarang, jalankan kode di atas seperti yang pertama dan kemudian coba jalankan dengan mengomentari setiap baris yang berisi breaksatu per satu dari bawah.

Rafiq
sumber
2

Cara mudah untuk mengubah banyak loop menjadi satu loop yang dapat diputuskan adalah dengan menggunakannya numpy.ndindex

for i in range(n):
  for j in range(n):
    val = x[i, j]
    break # still inside the outer loop!

for i, j in np.ndindex(n, n):
  val = x[i, j]
  break # you left the only loop there was!

Anda memang harus mengindeks ke objek Anda, sebagai lawan untuk dapat beralih melalui nilai-nilai secara eksplisit, tetapi setidaknya dalam kasus-kasus sederhana tampaknya sekitar 2-20 kali lebih sederhana daripada sebagian besar jawaban yang disarankan.

one_observation
sumber
2
# this version uses a level counter to choose how far to break out

break_levels = 0
while True:
    # snip: print out current state
    while True:
        ok = get_input("Is this ok? (y/n)")
        if ok == "y" or ok == "Y":
            break_levels = 1        # how far nested, excluding this break
            break
        if ok == "n" or ok == "N":
            break                   # normal break
    if break_levels:
        break_levels -= 1
        break                       # pop another level
if break_levels:
    break_levels -= 1
    break

# ...and so on
RufusVS
sumber
1

mungkin sedikit trik seperti di bawah ini akan dilakukan jika tidak lebih suka refactorial menjadi fungsi

menambahkan 1 variabel break_level untuk mengontrol kondisi loop sementara

break_level = 0
# while break_level < 3: # if we have another level of nested loop here
while break_level < 2:
    #snip: print out current state
    while break_level < 1:
        ok = get_input("Is this ok? (y/n)")
        if ok == "y" or ok == "Y": break_level = 2 # break 2 level
        if ok == "n" or ok == "N": break_level = 1 # break 1 level
Skycc
sumber
1

Anda dapat mendefinisikan variabel (misalnya break_statement ), kemudian mengubahnya ke nilai yang berbeda ketika kondisi dua-break terjadi dan menggunakannya dalam pernyataan if untuk break dari loop kedua juga.

while True:
    break_statement=0
    while True:
        ok = raw_input("Is this ok? (y/n)")
        if ok == "n" or ok == "N": 
            break
        if ok == "y" or ok == "Y": 
            break_statement=1
            break
    if break_statement==1:
        break
helmsdeep
sumber
Poin bagus, namun di setiap level di atas level minat dalam kita, kita perlu memindai variabel itu. Terasa sangat buruk bahwa bahasa tidak memiliki instruksi GoTo, kinerja-bijaksana.
Anatoly Alekseev
1

Saya ingin mengingatkan Anda bahwa fungsi dalam Python dapat dibuat tepat di tengah kode dan dapat mengakses variabel sekitarnya secara transparan untuk membaca dan dengan nonlocalatau globaldeklarasi untuk menulis.

Jadi, Anda dapat menggunakan fungsi sebagai "struktur kontrol yang dapat dipecah", menentukan tempat Anda ingin kembali ke:

def is_prime(number):

    foo = bar = number

    def return_here():
        nonlocal foo, bar
        init_bar = bar
        while foo > 0:
            bar = init_bar
            while bar >= foo:
                if foo*bar == number:
                    return
                bar -= 1
            foo -= 1

    return_here()

    if foo == 1:
        print(number, 'is prime')
    else:
        print(number, '=', bar, '*', foo)

>>> is_prime(67)
67 is prime
>>> is_prime(117)
117 = 13 * 9
>>> is_prime(16)
16 = 4 * 4
pengguna
sumber
1

Solusi dalam 2 Cara

Dengan sebuah contoh: Apakah kedua matriks ini sama / sama?
matrix1 dan matrix2 memiliki ukuran yang sama, n, 2 matriks dimensi.

Solusi Pertama , tanpa fungsi

same_matrices = True
inner_loop_broken_once = False
n = len(matrix1)

for i in range(n):
    for j in range(n):

        if matrix1[i][j] != matrix2[i][j]:
            same_matrices = False
            inner_loop_broken_once = True
            break

    if inner_loop_broken_once:
        break

Solusi Kedua , dengan fungsi
Ini adalah solusi terakhir untuk kasus saya

def are_two_matrices_the_same (matrix1, matrix2):
    n = len(matrix1)
    for i in range(n):
        for j in range(n):
            if matrix1[i][j] != matrix2[i][j]:
                return False
    return True

Semoga harimu menyenangkan!

Harun Altay
sumber
1
# this version breaks up to a certain label

break_label = None
while True:
    # snip: print out current state
    while True:
        ok = get_input("Is this ok? (y/n)")
        if ok == "y" or ok == "Y":
            break_label = "outer"   # specify label to break to
            break
        if ok == "n" or ok == "N":
            break
    if break_label:
        if break_label != "inner":
            break                   # propagate up
        break_label = None          # we have arrived!
if break_label:
    if break_label != "outer":
        break                       # propagate up
    break_label = None              # we have arrived!

#do more processing with menus and stuff
RufusVS
sumber
0

Semoga ini membantu:

x = True
y = True
while x == True:
    while y == True:
         ok = get_input("Is this ok? (y/n)") 
         if ok == "y" or ok == "Y":
             x,y = False,False #breaks from both loops
         if ok == "n" or ok == "N": 
             break #breaks from just one
Daniel L.
sumber
0

Berikut ini adalah implementasi yang tampaknya berhasil:

break_ = False
for i in range(10):
    if break_:
        break
    for j in range(10):
        if j == 3:
            break_ = True
            break
        else:
            print(i, j)

Satu-satunya penarikan adalah bahwa Anda harus mendefinisikan break_sebelum loop.

Fateh
sumber
0

Tidak ada cara untuk melakukan ini dari tingkat bahasa. Beberapa bahasa memiliki goto yang lain memiliki jeda yang membutuhkan argumen, python tidak.

Pilihan terbaik adalah:

  1. Atur bendera yang diperiksa oleh loop luar, atau atur kondisi loop luar.

  2. Letakkan loop dalam suatu fungsi dan gunakan kembali untuk keluar dari semua loop sekaligus.

  3. Merumuskan kembali logika Anda.

Kredit diberikan kepada Vivek Nagarajan, Programmer sejak 1987


Menggunakan Fungsi

def doMywork(data):
    for i in data:
       for e in i:
         return 

Menggunakan bendera

is_break = False
for i in data:
   if is_break:
      break # outer loop break
   for e in i:
      is_break = True
      break # inner loop break
Muhammad Faizan Fareed
sumber
-3

Mirip seperti sebelumnya, tetapi lebih ringkas. (Booleans hanya angka)

breaker = False #our mighty loop exiter!
while True:
    while True:
        ok = get_input("Is this ok? (y/n)")
        breaker+= (ok.lower() == "y")
        break

    if breaker: # the interesting part!
        break   # <--- !
alu5
sumber
2
Ini terlihat sangat jelek dan membuat kode lebih sulit untuk dipahami, dibandingkan dengan yang sebelumnya. Juga salah. Itu meleset pada benar-benar memeriksa apakah input dapat diterima dan rusak setelah 1 loop.
Eric
-3

Karena pertanyaan ini telah menjadi pertanyaan standar untuk membobol lingkaran tertentu, saya ingin memberikan jawaban saya dengan menggunakan contoh Exception .

Meskipun tidak ada label yang bernama breaking of loop dalam konstruk yang dilipatgandakan secara berulang, kita dapat menggunakan Pengecualian Buatan Pengguna untuk memecah menjadi loop tertentu dari pilihan kita. Pertimbangkan contoh berikut di mana mari kita mencetak semua angka hingga 4 digit dalam sistem penomoran basis-6:

class BreakLoop(Exception):
    def __init__(self, counter):
        Exception.__init__(self, 'Exception 1')
        self.counter = counter

for counter1 in range(6):   # Make it 1000
    try:
        thousand = counter1 * 1000
        for counter2 in range(6):  # Make it 100
            try:
                hundred = counter2 * 100
                for counter3 in range(6): # Make it 10
                    try:
                        ten = counter3 * 10
                        for counter4 in range(6):
                            try:
                                unit = counter4
                                value = thousand + hundred + ten + unit
                                if unit == 4 :
                                    raise BreakLoop(4) # Don't break from loop
                                if ten == 30: 
                                    raise BreakLoop(3) # Break into loop 3
                                if hundred == 500:
                                    raise BreakLoop(2) # Break into loop 2
                                if thousand == 2000:
                                    raise BreakLoop(1) # Break into loop 1

                                print('{:04d}'.format(value))
                            except BreakLoop as bl:
                                if bl.counter != 4:
                                    raise bl
                    except BreakLoop as bl:
                        if bl.counter != 3:
                            raise bl
            except BreakLoop as bl:
                if bl.counter != 2:
                    raise bl
    except BreakLoop as bl:
        pass

Ketika kita mencetak output, kita tidak akan pernah mendapatkan nilai yang unit place-nya dengan 4. Dalam hal itu, kita tidak putus dari loop apa pun seperti BreakLoop(4)dinaikkan dan ditangkap dalam loop yang sama. Demikian pula, setiap kali sepuluh tempat memiliki 3, kita masuk ke loop ketiga menggunakan BreakLoop(3). Setiap kali seratus tempat memiliki 5, kita masuk ke loop kedua menggunakan BreakLoop(2)dan ketika ribuan tempat memiliki 2, kita masuk ke loop pertama menggunakanBreakLoop(1) .

Singkatnya, naikkan Pengecualian Anda (bawaan atau yang ditentukan pengguna) di loop bagian dalam, dan tangkap di loop dari tempat Anda ingin melanjutkan kontrol. Jika Anda ingin istirahat dari semua loop, tangkap Pengecualian di luar semua loop. (Saya belum menunjukkan kasus ini sebagai contoh).

Prasad
sumber