Birden fazla döngü nasıl kesilir?


480

Aşağıdaki kod verildiğinde (işe yaramaz):

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

Bu işi yapmanın bir yolu var mı? Yoksa giriş döngüsünü kırmak için bir kontrol yapmam gerekiyor mu, daha sonra başka bir, daha sınırlı, kullanıcı memnun kaldığında hep birlikte ayrılmak için dış döngüyü kontrol et?


87
Python neden n 'kırmak istediğiniz düzeylerin sayısı olduğu' break (n) 'ye sahip değil.
Nathan

2
C ++, gotodöngülerin derinlerinde yuvalanmışsanız burada güzel
Drake Johnson

Yanıtlar:


512

İlk içgüdüm, iç içe döngüyü bir işleve yeniden yansıtmak ve returnpatlak vermek için kullanmak olurdu .


3
Bu başka bir düşünce vardı, çünkü get_input_yn () işlevi başka bir yerde de yararlı olacaktır, eminim.
Matthew Scharley

96
Bu özel durumda kabul etti, ancak genel 'iç içe döngüler var, ne yapacağım' yeniden düzenleme mantıklı olmayabilir.
quick_dry

return kullanmak yerine vermeniz gerektiğinde bir istisna kullanmak daha kolay olabilir, ancak böyle bir durumda muhtemelen itertools.islice () kullanmalısınız.
Robert

5
İç döngüyü kendi yöntemine yeniden yansıtmak genellikle mümkündür, bu da devam etmek için doğru, dış döngüyü kırmak için yanlış döndürür. while condition1: / değilse MyLoop2 (params): kesinti. Bir alternatif, her iki düzeyde de test edilen bir boole bayrağı ayarlamaktır. daha = Doğru / iken koşul1 ve daha: / iken koşul2 ve daha fazlası: / eğer stopCondition: Daha fazla = False / molası / ...
ToolmakerSteve

7
Kullanmaya returnçalışmanın doğru yaklaşım olduğuna katılıyorum . Ve akıl yürütme, Python Zen'e göre , "düz iç içe olmaktan daha iyidir" dir. Burada üç iç içe yerleştirme seviyemiz var ve bu yoldan çıkmaya başlarsa, iç içe geçirmeyi azaltmanın veya en azından tüm iç içe geçmeyi kendi işlevine çıkarma zamanı.
Lutz Prechelt

240

İşte kısa olan başka bir yaklaşım. Dezavantajı, sadece dış döngüyü kırabilmenizdir, ancak bazen tam olarak istediğiniz şeydir.

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

Bu, şu adreste açıklanan for / else yapısını kullanır: Python for ve while döngülerinden sonra neden 'else' kullanır?

Anahtar fikir: Sadece görünüyor hep dış döngü kırılır sanki. Ancak iç döngü kırılmazsa, dış döngü de olmaz.

Buradaki continueaçıklama sihirdir. Başka bir maddede. Tanım gereği , içsel bir mola yoksa olur. Bu durumda continuedış kopmayı düzgün bir şekilde atlar.


6
@eugeney Neden olmasın? İlk mola iç döngüden çıkar.
Navin

5
@eugeney Burada bir şey eksikmişim gibi hissediyorum. Bir örnek gönderebilir misiniz?
Navin

4
@Mingliang devam etmeden önce gidebilir.
Baldrickk

1
Bunu bir Raymond Hettinger videosu olan youtu.be/OSGv2VnC0go?t=971 , döngüler için "no_break" olarak eklenen "else" ifadelerini okuyun, sonra anlaşılması kolaylaşır.
Ambareesh

2
Bu akıllıca. :-) Ancak, düz ileri değil. Açıkçası, etiketli kırılma veya kırılma (n) 'yi Python'dan uzak tutmaya ikna olmadım. Geçici çözümler daha fazla karmaşıklık sağlar.
rfportilla

148

PEP 3136 etiketli kesme / devam etmeyi önerir. Guido bunu reddetti çünkü "bu özelliği gerektirecek kadar karmaşık kodlar çok nadir". PEP, bazı istisnalardan bahsetmektedir (istisna tekniği gibi), Guido çoğu durumda geri dönüşü kullanmak için yeniden düzenlemenin daha kolay olacağını düşünmektedir.


73
Refactor / returngenellikle gitmenin bir yolu olmasına rağmen, basit bir özlü break 2ifadenin çok mantıklı olacağı birkaç vaka gördüm . Ayrıca, refactor / returniçin aynı şekilde çalışmaz continue. Bu durumlarda, sayısal koparma ve devam etmenin izlenmesi, küçük bir işleve yeniden düzenleme yapmaktan, istisnaları yükseltmekten veya her yuva düzeyinde kırılacak bir bayrak ayarlamayı içeren kıvrık mantıktan daha kolay takip edilir ve daha az karmaşıktır. Guido'nun reddettiği bir utanç.
James Haigh

10
break; breakgüzel olurdu.
PyRulez

5
@Jeyekomon Sorun, bunun bir sorun olması için 3 veya daha fazla iç içe döngüye ihtiyacınız olmamasıdır. 2 iç içe döngü oldukça yaygındır
Jon

6
Msgstr "Bu özelliği gerektirecek kadar karmaşık kod çok nadirdir". Ancak, bu karmaşık kodu kullanırsanız, etiketli döngülerin olmaması onu daha da karmaşık hale getirecektir, çünkü breaktüm döngülerden manuel olarak iletmeniz gerekir . Aptal.
BallpointBen

3
Görünüşe göre, bir yayını sadece 5 dakika boyunca düzenleyebilirim (6 idi). Yani, düzenlediğim gönderi: 2 sentim: Perl, bir sonraki yinelemeye geçmek için break (ancak 'son' olarak adlandırıyor) ve 'next' olarak etiketledi. Hiç de nadir değil - her zaman kullanıyorum. Python'da yeniyim ve zaten buna ihtiyacım var. Ayrıca, numaralandırılmış aralar yeniden düzenleme için korkunç olurdu - kopmak istediğiniz döngüyü etiketlemek daha iyi, daha sonra hangi döngüyü çıkarmak istediğinizi açıkça belirtmek için break <label> kullanın.
John Deighan

119

İlk olarak, sıradan mantık yardımcı olur.

Herhangi bir nedenle, sonlandırma koşulları çözülemezse, istisnalar bir geri dönüş planıdır.

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

Bu özel örnek için bir istisna gerekli olmayabilir.

Diğer yandan, karakter modu uygulamalarında genellikle "Y", "N" ve "Q" seçeneklerimiz vardır. "Q" seçeneği için hemen çıkış yapmak istiyoruz. Bu daha istisnai.


4
Cidden, istisnalar son derece ucuz ve deyimsel python çok ve çok kullanıyor. Özel olanları tanımlamak ve atmak da çok kolaydır.
Gregg Lind

13
İlginç fikir. Sevip sevmeme ya da nefret etme konusunda paramparça oldum.
Craig McQueen

8
İki varyasyonun ayrı ayrı gösterilmesi halinde bu çözüm daha faydalı olacaktır. (1) bir bayrak ( done) kullanarak . (2) bir istisna oluşturmak. Bunları tek bir çözümde birleştirmek, karmaşık görünmesini sağlar. Gelecekteki okuyucular için: EITHER ilgili tüm satırları kullanın done, VEYA GetOutOfLoop(Exception)bunun dışında tanımlayın ve yükseltin.
ToolmakerSteve

4
Genel olarak, istisnalar dışında herhangi bir şey için try-block kullanımı çok kaşlarını çattı. Try-bloklar özellikle hata işleme için tasarlanmıştır ve bunları garip bir kontrol akışı için kullanmak, stilistik olarak çok iyi değildir.
nobillygreen

3
@ tommy.carstensen Bu saçmalık; hem yeni bir istisna alt sınıfının tanımlanması hem de yükseltilmesi (yanıtta gösterildiği gibi) ve yapıcıya Exception(ör. raise Exception('bla bla bla')) özel bir mesaj iletilmesi hem Python 2 hem de Python 3 için geçerlidir. bizim exceptblok yakalamak için tüm istisnaları, ama sadece özel istisna biz döngü çıkmak için kullanıyoruz. İşleri önerdiğiniz şekilde yaparsak ve kodumuzdaki bir hata beklenmedik bir istisnanın yükselmesine neden olursa, yanlışlıkla döngüden çıkmakla aynı şekilde ele alınır.
Mark Amery

54

Bir işleve yeniden düzenlemenin genellikle bu tür bir durum için en iyi yaklaşım olduğunu kabul etme eğilimindeyim, ancak iç içe döngülerden gerçekten ayrılmanız gerektiğinde, burada @ S.Lott'un açıkladığı istisna yaratma yaklaşımının ilginç bir varyantı. withİstisna yükseltme işleminin biraz daha hoş görünmesi için Python'un ifadesini kullanır . Şununla yeni bir içerik yöneticisi tanımlayın (bunu yalnızca bir kez yapmanız gerekir):

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

Şimdi bu bağlam yöneticisini aşağıdaki gibi kullanabilirsiniz:

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"

Avantajları: (1) biraz daha temiz (açık deneme hariç blok hariç) ve (2) Exceptionher kullanım için özel olarak inşa edilmiş bir alt sınıf elde edersiniz nested_break; Exceptionher seferinde kendi alt sınıfınızı beyan etmeye gerek yoktur .


40

İlk olarak, girişi alma ve onaylama işlemini bir işlev haline getirmeyi de düşünebilirsiniz; bu işlev içinde, değeri doğruysa döndürebilir ve eğer değilse while döngüsünde dönmeye devam edebilirsiniz . Bu aslında çözdüğünüz sorunu ortadan kaldırır ve genellikle daha genel bir durumda uygulanabilir (çoklu döngülerden kurtulma). Bu yapıyı kesinlikle kodunuzda tutmanız gerekiyorsa ve gerçekten defter tutma booleans ile uğraşmak istemiyorsanız ...

Goto'yu aşağıdaki şekilde de kullanabilirsiniz (April Fools modülünü buradan kullanarak ):

#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

Biliyorum, biliyorum, "gitmeyeceksin" ve tüm bunlar, ama bunun gibi garip durumlarda iyi çalışır.


1
INTERCAL'deki COME FROM komutu gibi bir şeyse, o zaman hiçbir şey
1800 BİLGİ

3
şaka gibi, ama yığın taşma noktası iyi kodu teşvik etmektir, bu yüzden size oy vermek zorunda :(
Christian Oudard

13
İyi bir kod olarak nitelendirmek için temiz ve okunabilir bir çözüm olduğunu düşünüyorum, bu yüzden oy kullanıyorum. :)
JT Hurley

1
@JTHurley hayır bu temiz ve okunaklı değil. Yani, bu örnekte temiz ve okunabilir gibi görünebilir, ancak herhangi bir gerçek yaşam senaryosunda kutsal bir karışıklık yaratır . (Ayrıca bu sooo anti-
pitonik

2
goto kötü bir temsilci alır, herhangi bir profesyonel kodlayıcı bence düzgün bir şekilde idare edebilmelidir.
Albert Renshaw

33

'Döngü kesici' olarak kullanacağınız yeni bir değişken tanıtın. Önce ona bir şey atayın (Yanlış, 0 vb.) Ve sonra dış döngü içinde, ondan ayrılmadan önce değeri başka bir şeye değiştirin (Doğru, 1, ...). Döngü çıktıktan sonra 'üst' döngü bu değeri kontrol edin. Göstereyim:

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

Sonsuz bir döngünüz varsa, tek çıkış yolu budur; diğer döngüler için yürütme gerçekten çok daha hızlı. Bu, birçok iç içe döngünüz varsa da işe yarar. Hepsinden veya sadece birkaç tanesinden çıkabilirsiniz. Sonsuz olasılıklar! Umarım bu yardımcı oldu!


22

Bir işleve yeniden düzenleme yapmadan birden çok iç içe döngüden çıkmak için, yerleşik StopIteration istisnasıyla bir "simüle edilmiş goto deyimi" kullanın :

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

except StopIteration: pass

Yuvalanmış döngülerden kurtulmak için goto ifadelerinin kullanımı hakkındaki bu tartışmaya bakın .


1
Bu, istisnayı ele almak için kendi sınıfınızı oluşturmaktan çok daha hoş görünüyor ve çok temiz görünüyor. Bunu yapmamam için bir sebep var mı?
mgjk

Aslında StopIteration jeneratörler için kullanıyor, ama normalde herhangi bir benzersiz StopIteration istisnası olmadığını düşünüyorum. Bu yüzden iyi bir çözüm gibi görünüyor ama yine de yeni bir istisna yaratmada bir hata yok.
Kowalski

1
Benim için en iyi ve en basit çözüm
Alexandre Huat

16

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

ya da böyle bir şey. İç döngüde bir değişken ayarlayabilir ve iç döngü çıktıktan hemen sonra dış döngüde kontrol edebilir, uygunsa kesebilirsiniz. Bir April Fool'un şaka modülünü kullanmamanız koşuluyla GOTO yöntemini beğendim - Pythonic değil, ama mantıklı.


Bu bir çeşit bayrak ayarı!
SIslam

Bence çok iyi bir çözüm.
Kowalski

13

Bunu yapmanın en güzel yolu değil, ama bence en iyi yol.

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

Burada da özyineleme kullanarak bir şeyler çalıştırabileceğinize eminim, ama sizin için iyi bir seçenek olup olmadığını bilmiyorum.


Bu benim için doğru çözümdü. Kullanım durumum OP'lerden çok farklıydı. Ben permütasyonları bulmak için aslında aynı veri üzerinde iki kez döngü oldu, bu yüzden iki while döngülerini ayırmak istemiyordu.
Brian Peterson

9

Ve iki koşul doğruysa neden döngü yapmaya devam etmiyorsunuz? Bunun daha pitonik bir yol olduğunu düşünüyorum:

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

Öyle değil mi?

Herşey gönlünce olsun.


neden sadece while dejaVu:? Yine de true değerine ayarladınız.
Matthew Scharley

hey işe yarıyor! İki Truedurumda iki döngüyü atlamayı düşünüyordum , ama sadece bir tane yeterli.
Mauro Aspé

2
@MatthewScharley Bunun iç içe döngülerde çalıştığını göstermek olduğunu düşünüyorum.
sap

@ MauroAspé bu OP'nin istediklerini tam olarak yapmayacak. yine de tüm dış döngüyü yürütür, ancak hedef kodun geri kalanını
kırmazsanız

@yamm Bu if not dejaVu: break, alttaki a ile çözülemez ve bu nedenle ana döngüden çıkartılamaz mı? Çözümün, sorulan soruya en yakın olduğunu düşünüyorum. +1
milcak

8

Döngü mantığınızı, döngü değişkenlerini veren ve bittiğinde dönen bir yineleyiciye katlayın - işte, görüntülerden çıkana veya yerleştirilecek yerlerden çıkana kadar görüntüleri satır / sütunlara yerleştiren basit bir yöntem:

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 ...

Bu, karmaşık döngü mantığını ve işlemeyi bölme avantajına sahiptir ...


3

Bu durumda, başkaları tarafından da belirtildiği gibi, işlevsel ayrışma yoludur. Python 3'teki kod:

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

3

Python while ... elseyapısında, çok fazla kod değişikliği / eklemesi olmadan çift kesmeyi simüle etmek için kullanılabilecek gizli bir numara var . Özünde whilekoşul yanlışsa, elseblok tetiklenir. İstisnalar continueya breakda elsebloğu tetiklemeyin . Daha fazla bilgi için bkz. " Python while deyimindeki Else yan tümcesi " veya while (v2.7) adlı Python doc .

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

Tek dezavantajı, çift kesme koşulunu koşula taşımanız while(veya bir bayrak değişkeni eklemeniz) gerekmesidir . Bunun varyasyonları for, elsebloğun döngü tamamlandıktan sonra tetiklendiği döngü için de vardır.


Bu, çift mola şartını yerine getirmiyor gibi görünüyor. Kesin verilen sorun için çalışır, ancak asıl soru için değil.
Dakkaron

@Dakkaron Kodu doğru anladığınızdan emin misiniz? Kod gerçekten OP sorusunu çözer ve isteğe benzer keser. Bununla birlikte, çoklu döngülerden kopmaz, ancak molayı ikiye katlama ihtiyacını değiştirmek için else yan tümcesini kullanın.
holroy

Anladığım kadarıyla soru şuydu How to break out of multiple loops in Python?ve cevap "Bu işe yaramıyor, başka bir şey denemek" olmalı. OP'nin verilen belirli örneğini düzelttiğini biliyorum, ancak sorularına cevap vermiyor.
Dakkaron

@Dakkaron, Kod altındaki sorun ifadesine bakın ve bence OP'ler sorusuna gerçekten cevap veriyor.
holroy

2

Tek seviyeli bir döngüye yinelemeyi azaltmanın başka bir yolu, python referansında da belirtildiği gibi jeneratörlerin kullanılmasıdır.

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

Döngü için istediğiniz sayıda seviyeye ölçeklendirebilirsiniz

Dezavantajı, artık sadece tek bir seviyeyi kıramayacağınızdır. Ya hep ya hiç.

Başka bir dezavantajı ise while döngüsü ile çalışmaz. Aslında bu cevabı Python'a göndermek istedim - tüm döngülerden `` kopar '' ama maalesef bu bir kopya olarak kapalı


1
Döngüler için de çalışır, jeneratörünüzü bir kavrama olarak değil, sadece bir def (verim ile) olarak yazmanız gerekir.
Veky

Evet, bir PyCon konuşmacısı burada @ RobertRossney'nin kabul ettiği cevabın bile gerçekten Pythonic olmadığını iddia ediyor , ancak bir jeneratör birden fazla döngüyü kırmanın doğru yolu. (Tüm videoyu izlemenizi tavsiye ederim!)
Post169

2

Buraya gelmek için benim neden bir dış döngü ve böyle bir iç döngü vardı:

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

Gördüğünüz gibi, aslında bir sonraki x'e gitmez, bunun yerine bir sonraki y'ye gider.

Bu sadece çözmek için buldum bunun yerine iki kez dizi üzerinden çalıştırmak oldu:

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

Bunun OP'nin sorusunun belirli bir vakası olduğunu biliyorum, ancak bir şeyi basit tutarken birilerinin problemleri hakkında farklı düşünmesine yardımcı olacağı umuduyla gönderiyorum.


Bu muhtemelen Python değil. Dizi türü nedir? Muhtemelen listeliyor, ama ne içeriyor? İnts içeriyor olsa bile, array.pop (x) muhtemelen istediğinizi yapmayacaktır.
Veky

İyi bir noktaya değindin. Referans verdiğim kodu bulamıyorum. Bunu okuyan herkes için array.pop (i) "i dizinine sahip öğeyi diziden kaldırır ve döndürür." python belgelerine göre. Bu nedenle, bu kodun beklendiği gibi çalışması için dizideki x öğesinin dizinini alması gerekir. Ayrıca beklenen şeyi yapacak array.remove (x) işlevi de vardır. Bu hatayı düzeltmek için yukarıdaki cevabımı değiştireceğim. Bu, ikinci dizinin yineleme içermediğini varsayar, çünkü array.remove (x), bulunan x'in yalnızca ilk örneğini kaldırır.
Nathan Garabedian

Tamam, sonra anladım. Bu durumda, sadece breakyerine kullanmak continueistediğinizi yaparsınız, değil mi? :-)
Veky

Evet, verimlilik ve netlik için muhtemelen bu örneklerde devam etmek yerine mola vermek istersiniz. :)
Nathan Garabedian

2

Sonsuz bir jeneratör kullanmayı deneyin.

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

2

Bir işlev kullanarak:

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()

Yukarıdaki kodları da yorumlayarak çalıştırmayı deneyin return.

Herhangi bir işlev kullanmadan:

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

Şimdi, yukarıdaki kodları ilk önce olduğu gibi çalıştırın ve daha sonra her breakbirini birer birer alttan yorumlayarak çalıştırmayı deneyin .


2

Birden fazla döngüyü tek, kırılabilir bir döngüye dönüştürmenin kolay bir yolu kullanmaktır 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!

Değerleri açıkça yineleyebilmenin aksine, nesnelerinize endekslemeniz gerekir, ancak en azından basit durumlarda önerilen cevapların çoğundan yaklaşık 2-20 kat daha basit gibi görünmektedir.


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

1

Muhtemelen aşağıdaki gibi küçük hile işlevine refaktöryel tercih etmeyecek

while döngüsü koşulunu kontrol etmek için 1 break_level değişkeni eklendi

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

1

Bir değişken tanımlayabilirsiniz (örneğin break_statement ), sonra iki kesme koşulu oluştuğunda bunu farklı bir değere değiştirebilir ve eğer ikinci döngüden kopmak için if deyiminde kullanabilirsiniz.

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

İyi bir nokta, ancak iç ilgi seviyemizin üzerindeki seviyelerin her birinde bu değişkeni taramamız gerekir. Dilin performans açısından bir GoTo talimatı olmaması gerçekten kötü hissettiriyor.
Anatoly Alekseev

1

Python'daki işlevlerin kodun tam ortasında oluşturulabileceğini ve çevredeki değişkenlere okuma için ve yazma için nonlocalveya globalbildirimle birlikte şeffaf bir şekilde erişebileceğini hatırlatmak isterim .

Böylece, bir işlevi "kırılabilir kontrol yapısı" olarak kullanarak geri dönmek istediğiniz bir yeri tanımlayabilirsiniz:

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

1

2 Yönlü Çözümler

Bir örnekle: Bu iki matris eşit / aynı mı?
matris1 ve matris2 aynı boyutta, n, 2 boyutlu matrislerdir.

İlk Çözüm , işlevsiz

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

İkinci Çözüm , bir işlevle
Bu benim durum için nihai çözümdür

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

İyi günler!


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

0

Umarım bu yardımcı olur:

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

0

İşte işe yarayan bir uygulama:

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)

Tek dezavantajı break_, döngülerden önce tanımlamanız gerektiğidir .


0

Bunu dil seviyesinden yapmanın bir yolu yok. Bazı dillerin goto var, diğerlerinin argüman alan bir molası var, python yok.

En iyi seçenekler:

  1. Dış döngü tarafından kontrol edilen bir bayrak ayarlayın veya dış döngüler koşulunu ayarlayın.

  2. Döngüyü bir işleve yerleştirin ve bir kerede tüm döngülerden çıkmak için return tuşunu kullanın.

  3. Mantığınızı yeniden düzenleyin.

Kredi 1987'den beri Programcı Vivek Nagarajan'a gidiyor


İşlev Kullanımı

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

Bayrak kullanma

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

-3

Daha öncekine benzer, ancak daha kompakt. (Boolean'lar sadece rakamlardır)

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   # <--- !

2
Bu oldukça çirkin görünüyor ve kodun bir öncekine kıyasla anlaşılmasını zorlaştırıyor. Ayrıca, yanlış. Girişin kabul edilebilir olup olmadığını gerçekten kontrol eder ve 1 döngüden sonra kesilir.
Eric

-3

Bu soru belirli bir döngüye girmek için standart bir soru haline geldiğinden, cevabımı örnek kullanımıyla vermek istiyorum Exception.

Çok döngülü yapıda döngü kırma adında bir etiket olmamasına rağmen, seçtiğimiz belirli bir döngüye girmek için Kullanıcı Tanımlı İstisnalar kullanabiliriz. Base-6 numaralandırma sisteminde 4 rakama kadar tüm sayıları yazdıracağımız aşağıdaki örneği düşünün:

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

Çıktıyı yazdırdığımızda, birim yeri 4 olan hiçbir değer elde etmeyeceğiz. Bu durumda, BreakLoop(4)yükseltilmiş ve aynı döngüye yakalanmış hiçbir döngüden kopmazız. Benzer şekilde, her on yer 3 olduğunda, üçüncü döngüye gireriz BreakLoop(3). Her ne zaman yüz yer 5 olursa, ikinci döngüye BreakLoop(2)gireriz ve bin yer 2 olduğunda, ilk döngüye girerizBreakLoop(1) .

Kısacası, istisnaınızı (dahili veya kullanıcı tanımlı) iç döngülerde yükseltin ve kontrolünüzü devam ettirmek istediğiniz yerden döngüde yakalayın. Tüm döngülerden kopmak istiyorsanız, istisnayı tüm döngülerin dışında yakalayın. (Bu örneği örnekte göstermedim).

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.