Làm thế nào để thoát ra khỏi nhiều vòng lặp?


481

Cho mã sau (không hoạt động):

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

Có cách nào để làm cho công việc này? Hoặc tôi có thực hiện một kiểm tra để thoát ra khỏi vòng lặp đầu vào, sau đó kiểm tra khác, hạn chế hơn, kiểm tra trong vòng lặp bên ngoài để thoát ra tất cả cùng nhau nếu người dùng hài lòng?


87
Tại sao Python không có 'break (n)' trong đó n là số cấp bạn muốn thoát ra.
Nathan

2
C ++ ở đây rất tuyệt gotonếu bạn nép mình sâu trong nhiều vòng lặp
Drake Johnson

Câu trả lời:


512

Bản năng đầu tiên của tôi sẽ là cấu trúc lại vòng lặp lồng vào một hàm và sử dụng returnđể thoát ra.


3
Đây là một suy nghĩ khác mà tôi có, vì hàm get_input_yn () cũng sẽ hữu ích ở những nơi khác, tôi chắc chắn.
Matthew Scharley

96
đồng ý trong trường hợp cụ thể này, nhưng trong trường hợp chung của 'Tôi có các vòng lặp lồng nhau, tôi phải làm gì' tái cấu trúc có thể không có ý nghĩa.
quick_dry

sử dụng một ngoại lệ có thể dễ dàng hơn khi bạn phải mang lại thay vì sử dụng return, tuy nhiên có lẽ bạn nên sử dụng itertools.islice () trong trường hợp như vậy.
vua robert

5
Thông thường có thể cấu trúc lại vòng lặp bên trong thành phương thức riêng của nó, trả về true để tiếp tục, false để phá vỡ vòng lặp bên ngoài. while condition1: / if not MyLoop2 (params): break. Một cách khác là đặt cờ boolean, được thử nghiệm ở cả hai cấp độ. more = True / while condition1 trở lên: / while condition2 trở lên: / if stopCondition: more = false / break / ...
ToolmakerSteve

7
Tôi đồng ý rằng phấn đấu để sử dụng returnlà phương pháp đúng đắn. Và lý do là, theo Zen of Python , "căn hộ tốt hơn lồng nhau". Chúng ta có ba cấp độ lồng ở đây và nếu điều đó bắt đầu cản trở, đã đến lúc giảm việc làm tổ hoặc ít nhất là trích xuất toàn bộ việc làm tổ thành một chức năng của riêng nó.
Lutz Prechelt

240

Đây là một cách tiếp cận ngắn. Nhược điểm là bạn chỉ có thể phá vỡ vòng lặp bên ngoài, nhưng đôi khi nó chính xác là những gì bạn muốn.

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

Điều này sử dụng cấu trúc for / other được giải thích tại: Tại sao python sử dụng 'other' sau vòng lặp for và while?

Thông tin chi tiết chính: Có vẻ như nếu vòng lặp bên ngoài luôn luôn bị phá vỡ. Nhưng nếu vòng lặp bên trong không bị phá vỡ, vòng lặp bên ngoài sẽ không.

Các continuetuyên bố là sự kỳ diệu ở đây. Đó là trong mệnh đề for-other. Theo định nghĩa đó sẽ xảy ra nếu không có sự phá vỡ bên trong. Trong tình huống đó continuegọn gàng phá vỡ các phá vỡ bên ngoài.


6
@eugeney Tại sao không? Sự phá vỡ đầu tiên sẽ ra khỏi vòng lặp bên trong.
Navin

5
@eugeney Tôi cảm thấy như mình đang thiếu thứ gì đó ở đây. Bạn có thể gửi một ví dụ?
Navin

4
@Mingliang có thể đi trước khi tiếp tục.
Baldrickk

1
Nhận được điều này từ video Raymond Hettinger, youtu.be/OSGv2VnC0go?t=971 , đọc các câu lệnh "khác" được đính kèm cho các vòng lặp là "no_break", sau đó nó trở nên dễ hiểu hơn.
Ambareesh

2
Đây là thông minh. :-) Tuy nhiên, không đơn giản. Thành thật mà nói, tôi không bị thuyết phục bởi các đối số để giữ cho break hoặc break (n) ra khỏi Python. Các cách giải quyết thêm phức tạp.
rfportilla

148

PEP 3136 đề xuất phá vỡ / tiếp tục dán nhãn. Guido đã từ chối vì "mã quá phức tạp để yêu cầu tính năng này là rất hiếm". PEP có đề cập đến một số cách giải quyết, mặc dù (chẳng hạn như kỹ thuật ngoại lệ), trong khi Guido cảm thấy việc tái cấu trúc để sử dụng trả lại sẽ đơn giản hơn trong hầu hết các trường hợp.


73
Mặc dù, refactor / returnthường là cách để đi, tôi đã thấy khá nhiều trường hợp trong đó một break 2câu lệnh ' ' súc tích đơn giản sẽ có ý nghĩa rất lớn. Ngoài ra, refactor / returnkhông hoạt động tương tự cho continue. Trong những trường hợp này, ngắt và tiếp tục số sẽ dễ theo dõi hơn và ít lộn xộn hơn so với tái cấu trúc thành một hàm nhỏ, đưa ra các ngoại lệ hoặc logic phức tạp liên quan đến việc đặt cờ ngắt ở mỗi cấp lồng. Thật xấu hổ khi Guido từ chối nó.
James Haigh

10
break; breaksẽ tốt.
PyRulez

5
@Jeyekomon Vấn đề là bạn không cần 3 vòng lặp lồng nhau trở lên để điều này trở thành một vấn đề. 2 vòng lặp lồng nhau khá phổ biến
Jon

6
"Mã rất phức tạp để yêu cầu tính năng này là rất hiếm". Nhưng nếu bạn đã từng sử dụng mã phức tạp này, việc thiếu các vòng lặp được gắn nhãn sẽ khiến nó trở nên phức tạp hơn nữa, vì bạn phải chuyển tiếp thủ công breakqua tất cả các vòng lặp. Ngốc nghếch.
BallpointBen

3
Rõ ràng, tôi chỉ có thể chỉnh sửa một bài đăng trong 5 phút (đã là 6). Vì vậy, đây là bài đăng đã được chỉnh sửa của tôi: 2 xu của tôi: Perl đã dán nhãn break (nhưng gọi đó là 'lần cuối') và 'tiếp theo' để tiếp tục trực tiếp đến lần lặp tiếp theo. Nó hoàn toàn không phải là hiếm - tôi sử dụng nó mọi lúc. Tôi hoàn toàn mới với Python và đã có nhu cầu về nó. Ngoài ra, các ngắt được đánh số sẽ là khủng khiếp đối với tái cấu trúc - tốt hơn là gắn nhãn cho vòng lặp mà bạn muốn thoát ra, sau đó sử dụng break <nhãn> để nói rõ ràng vòng lặp nào bạn muốn thoát ra.
John Deighan

119

Đầu tiên, logic thông thường là hữu ích.

Nếu, vì một số lý do, các điều kiện chấm dứt không thể được giải quyết, các trường hợp ngoại lệ là một kế hoạch dự phòng.

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

Đối với ví dụ cụ thể này, một ngoại lệ có thể không cần thiết.

Mặt khác, chúng ta thường có các tùy chọn "Y", "N" và "Q" trong các ứng dụng chế độ ký tự. Đối với tùy chọn "Q", chúng tôi muốn có một lối thoát ngay lập tức. Điều đó đặc biệt hơn.


4
Nghiêm túc mà nói, ngoại lệ là cực kỳ rẻ và trăn thành ngữ sử dụng rất nhiều và rất nhiều trong số họ. Nó cũng rất dễ dàng để xác định và ném những cái tùy chỉnh.
Gregg Lind

13
Ý tưởng thú vị. Tôi không biết nên yêu hay ghét nó.
Craig McQueen

8
Giải pháp này sẽ hữu ích hơn, nếu nó cho thấy hai biến thể riêng biệt. (1) sử dụng cờ ( done). (2) đưa ra một ngoại lệ. Hợp nhất chúng lại với nhau thành một giải pháp duy nhất chỉ khiến nó trông phức tạp. Đối với độc giả tương lai: EITHER sử dụng tất cả các dòng liên quan done, HOẶC xác định GetOutOfLoop(Exception)và nâng cao / ngoại trừ điều đó.
ToolmakerSteve 18/12/13

4
Nói chung, sử dụng các khối thử cho bất kỳ thứ gì khác ngoại lệ là rất khó chịu. Các khối thử được thiết kế đặc biệt để xử lý lỗi và sử dụng chúng cho một số luồng điều khiển lạ không tốt lắm, theo kiểu cách.
tộc

3
@ tommy.carstensen Điều đó thật vô nghĩa; cả hai đều xác định một lớp con ngoại lệ mới và nâng cao nó (như được hiển thị trong câu trả lời) và gửi một thông điệp tùy chỉnh đến hàm Exceptiontạo (ví dụ raise Exception('bla bla bla')) đều hợp lệ trong cả Python 2 và Python 3. Trường hợp này thích hợp hơn trong trường hợp này vì chúng tôi không muốn exceptkhối của chúng tôi để bắt tất cả các ngoại lệ, nhưng chỉ ngoại lệ đặc biệt chúng tôi đang sử dụng để thoát khỏi vòng lặp. Nếu chúng tôi thực hiện mọi thứ theo cách bạn đề xuất, và sau đó một lỗi trong mã của chúng tôi gây ra một ngoại lệ không mong muốn được đưa ra, nó sẽ bị xử lý sai giống như cố tình thoát khỏi vòng lặp.
Mark Amery

54

Tôi có xu hướng đồng ý rằng tái cấu trúc thành một hàm thường là cách tiếp cận tốt nhất cho loại tình huống này, nhưng khi bạn thực sự cần thoát ra khỏi các vòng lặp lồng nhau, đây là một biến thể thú vị của phương pháp nâng cao ngoại lệ mà @ S.Lott đã mô tả. Nó sử dụng withcâu lệnh của Python để làm cho ngoại lệ tăng lên trông đẹp hơn một chút. Xác định trình quản lý bối cảnh mới (bạn chỉ phải thực hiện việc này một lần) với:

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

Bây giờ bạn có thể sử dụng trình quản lý bối cảnh này như sau:

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"

Ưu điểm: (1) nó sạch hơn một chút (không có khối ngoại trừ thử rõ ràng) và (2) bạn có được một Exceptionlớp con được xây dựng tùy chỉnh cho mỗi lần sử dụng nested_break; không cần phải khai báo Exceptionlớp con của riêng bạn mỗi lần.


40

Đầu tiên, bạn cũng có thể xem xét làm cho quá trình nhận và xác nhận đầu vào thành một hàm; trong hàm đó, bạn có thể trả về giá trị nếu đúng và tiếp tục quay trong khi vòng lặp nếu không muốn nói. Điều này về cơ bản làm giảm bớt vấn đề bạn đã giải quyết và thường có thể được áp dụng trong trường hợp tổng quát hơn (thoát ra khỏi nhiều vòng lặp). Nếu bạn hoàn toàn phải giữ cấu trúc này trong mã của mình và thực sự không muốn đối phó với các booleans kế toán ...

Bạn cũng có thể sử dụng goto theo cách sau (sử dụng mô-đun Cá tháng Tư từ đây ):

#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

Tôi biết, tôi biết, "ngươi sẽ không sử dụng goto" và tất cả những thứ đó, nhưng nó hoạt động tốt trong những trường hợp lạ như thế này.


1
Nếu đó là bất cứ thứ gì giống như lệnh COME TỪ trong INTERCAL, thì không có gì
1800 THÔNG TIN

3
Tôi thích trò đùa, nhưng quan điểm của stack stack là để quảng bá mã tốt, vì vậy tôi phải bỏ phiếu cho bạn :(
Christian Oudard

13
Tôi nghĩ rằng đó là một giải pháp đủ sạch và dễ đọc để đủ điều kiện là mã tốt, vì vậy tôi bỏ phiếu. :)
JT Hurley

1
@JTHurley không cái này không sạch và dễ đọc. Ý tôi là, nó có thể trông như sạch sẽ và dễ đọc trong ví dụ này nhưng trong bất kỳ kịch bản đời thực nào, goto đều tạo ra một mớ hỗn độn thần thánh . (Ngoài ra, đây là sooo chống pythonic ...)
Alois Mahdal

2
Theo quan điểm của tôi, goto có một đại diện xấu, bất kỳ lập trình viên chuyên nghiệp nào cũng có thể xử lý nó đúng cách.
Albert Renshaw

33

Giới thiệu một biến mới mà bạn sẽ sử dụng làm 'bộ ngắt vòng'. Trước tiên, gán một cái gì đó cho nó (Sai, 0, v.v.), và sau đó, bên trong vòng lặp bên ngoài, trước khi bạn thoát khỏi nó, thay đổi giá trị thành một thứ khác (Đúng, 1, ...). Khi thoát khỏi vòng lặp, hãy kiểm tra vòng lặp 'cha mẹ' cho giá trị đó. Hãy để tôi chứng minh:

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

Nếu bạn có một vòng lặp vô hạn, đây là lối thoát duy nhất; thực hiện các vòng lặp khác thực sự nhanh hơn rất nhiều. Điều này cũng hoạt động nếu bạn có nhiều vòng lặp lồng nhau. Bạn có thể thoát tất cả, hoặc chỉ một vài. Khả năng vô tận! Hy vọng điều này sẽ giúp!


22

Để thoát ra khỏi nhiều vòng lặp lồng nhau, mà không tái cấu trúc thành một hàm, hãy sử dụng "câu lệnh goto mô phỏng" với ngoại lệ StopIteration tích hợp :

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

except StopIteration: pass

Xem cuộc thảo luận này về việc sử dụng các câu lệnh goto để thoát ra khỏi các vòng lặp lồng nhau.


1
Điều này trông đẹp hơn nhiều so với việc tạo lớp của riêng bạn để xử lý ngoại lệ và trông rất sạch sẽ. Có bất kỳ lý do tôi không nên làm điều này?
mgjk

Trong thực tế, StopIteration đang sử dụng cho các trình tạo, nhưng tôi nghĩ thông thường bạn không có bất kỳ ngoại lệ StopIteration nào chưa được ghép. Vì vậy, nó có vẻ như là một giải pháp tốt nhưng dù sao cũng không có lỗi khi tạo ngoại lệ mới.
Cửu Long

1
Giải pháp tốt nhất và đơn giản nhất cho tôi
Alexandre Huat

16

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

hoặc điều tương tự. Bạn có thể đặt một biến trong vòng lặp bên trong và kiểm tra nó trong vòng lặp bên ngoài ngay sau khi vòng lặp bên trong thoát ra, phá vỡ nếu thích hợp. Tôi giống như phương pháp GOTO, miễn là bạn không phiền khi sử dụng mô-đun trò đùa Cá tháng Tư - nó không phải là Pythonic, nhưng nó thực sự có ý nghĩa.


đây là loại thiết lập cờ!
SIslam

Tôi nghĩ đó là một giải pháp rất tốt.
Cửu Long

13

Đây không phải là cách đẹp nhất để làm điều đó, nhưng theo tôi, đó là cách tốt nhất.

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

Tôi khá chắc chắn rằng bạn cũng có thể tìm ra thứ gì đó bằng cách sử dụng đệ quy ở đây, nhưng tôi không biết nếu đó là một lựa chọn tốt cho bạn.


Đây là giải pháp phù hợp với tôi. Trường hợp sử dụng của tôi rất khác so với OP. Tôi đã lặp đi lặp lại trên cùng một dữ liệu hai lần để tìm hoán vị, vì vậy tôi không muốn tách hai vòng lặp.
Brian Peterson

9

Và tại sao không tiếp tục lặp nếu hai điều kiện là đúng? Tôi nghĩ rằng đây là một cách pythonic hơn:

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

Phải không?

Tất cả tốt nhất.


tại sao không chỉ while dejaVu:? Dù sao thì bạn cũng đặt nó thành true.
Matthew Scharley

này mà làm việc Tôi đã suy nghĩ trong hai Trueđiều kiện để bỏ qua hai vòng, nhưng chỉ cần một vòng là đủ.
Mauro Aspé

2
@MatthewScharley Tôi nghĩ rằng điều này là để cho thấy rằng điều này hoạt động trong các vòng lặp lồng nhau.
xử lý

@ MauroAspé điều này sẽ không thực hiện chính xác những gì OP yêu cầu. nó vẫn sẽ thực thi toàn bộ vòng lặp bên ngoài nhưng mục tiêu là nếu bạn phá vỡ phần còn lại của mã sẽ không được thực thi
yamm

@yamm Điều đó có thể không được giải quyết với một if not dejaVu: breakở phía dưới và do đó thoát khỏi vòng lặp chính? Tôi nghĩ rằng giải pháp là gần nhất với những gì đã được hỏi. +1
milcak

8

Yếu tố logic vòng lặp của bạn vào một trình vòng lặp mang lại các biến vòng lặp và trả về khi hoàn thành - đây là một cách đơn giản để đưa ra hình ảnh trong các hàng / cột cho đến khi chúng ta hết hình ảnh hoặc ra khỏi vị trí để đặt chúng:

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

Điều này có lợi thế là phân tách logic vòng lặp phức tạp và xử lý ...


3

Trong trường hợp này, như được chỉ ra bởi những người khác, phân rã chức năng là cách để đi. Mã trong 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

3

Có một mẹo ẩn trong while ... elsecấu trúc Python có thể được sử dụng để mô phỏng ngắt kép mà không cần thay đổi / bổ sung nhiều mã. Về bản chất nếu whileđiều kiện là sai, elsekhối được kích hoạt. Không có ngoại lệ, continuehoặc breakkích hoạt elsekhối. Để biết thêm thông tin, hãy xem câu trả lời cho " Điều khoản khác trên Python while statement " hoặc Python doc on while (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

Nhược điểm duy nhất là bạn cần di chuyển điều kiện ngắt kép vào whileđiều kiện (hoặc thêm một biến cờ). Biến thể của điều này cũng tồn tại đối với forvòng lặp, trong đó elsekhối được kích hoạt sau khi hoàn thành vòng lặp.


Điều này dường như không đáp ứng yêu cầu của nghỉ đôi. Hoạt động cho các vấn đề chính xác, nhưng không phải cho câu hỏi thực tế.
Dakkaron

@Dakkaron Bạn có chắc bạn đã hiểu mã chính xác? Mã thực sự giải quyết câu hỏi OP và phá vỡ tương tự như yêu cầu. Tuy nhiên, nó không thoát ra khỏi nhiều vòng lặp, nhưng sử dụng mệnh đề khác để thay thế cho nhu cầu nhân đôi số lần ngắt.
holroy

Theo hiểu biết của tôi, câu hỏi là How to break out of multiple loops in Python?và câu trả lời nên là "Nó không hoạt động, hãy thử một cái gì đó khác". Tôi biết nó sửa ví dụ chính xác của OP, nhưng không trả lời câu hỏi của họ.
Dakkaron

@Dakkaron, Xem báo cáo vấn đề theo mã, và theo tôi, nó thực sự trả lời câu hỏi OP.
holroy

2

Một cách khác để giảm số lần lặp của bạn xuống một vòng lặp cấp đơn sẽ thông qua việc sử dụng các trình tạo như được chỉ định trong tham chiếu python

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

Bạn có thể mở rộng nó tới bất kỳ số cấp nào cho vòng lặp

Nhược điểm là bạn không còn có thể phá vỡ chỉ một cấp độ duy nhất. Đó là tất cả hoặc không có gì.

Một nhược điểm khác là nó không hoạt động với vòng lặp while. Ban đầu tôi muốn đăng câu trả lời này lên Python - `break` trong tất cả các vòng lặp nhưng tiếc là nó đã bị đóng như một bản sao của câu hỏi này


1
Nó cũng hoạt động trong khi các vòng lặp, bạn chỉ cần viết trình tạo của bạn dưới dạng def (có năng suất), không phải là một sự hiểu biết.
Veky

Có, một diễn giả tại PyCon tuyên bố ở đây rằng ngay cả câu trả lời được chấp nhận của @ RobertRossney không thực sự là Pythonic, nhưng một máy phát điện là cách phù hợp để phá vỡ nhiều vòng lặp. (Tôi khuyên bạn nên xem toàn bộ video!)
Post169

2

Lý do tôi đến đây là tôi có một vòng lặp bên ngoài và một vòng lặp bên trong như vậy:

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

Như bạn có thể thấy, nó sẽ không thực sự đi đến x tiếp theo, mà sẽ chuyển sang y tiếp theo.

thay vào đó, điều tôi tìm thấy để giải quyết điều này chỉ đơn giản là chạy qua mảng hai lần:

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

Tôi biết đây là một trường hợp cụ thể của câu hỏi của OP, nhưng tôi đăng nó với hy vọng nó sẽ giúp ai đó nghĩ về vấn đề của họ một cách khác biệt trong khi giữ mọi thứ đơn giản.


Đây có lẽ không phải là Python. Các loại mảng là gì? Có lẽ danh sách, nhưng nó chứa những gì? Ngay cả khi nó chứa ints, mảng.pop (x) có thể sẽ không làm những gì bạn muốn.
Veky

Đó là một điểm hay. Tôi không thể tìm thấy mã mà tôi đã tham chiếu. Đối với bất kỳ ai đọc điều này, Array.pop (i) "Xóa mục có chỉ mục i khỏi mảng và trả về nó." theo tài liệu python. Vì vậy, người ta sẽ cần lấy chỉ mục của mục x trong mảng để làm cho mã này hoạt động như mong đợi. Ngoài ra còn có hàm Array.remove (x) sẽ làm những gì được mong đợi. Tôi sẽ sửa đổi câu trả lời của tôi ở trên để sửa lỗi đó. Điều này giả sử mảng thứ hai không chứa các bản sao, vì mảng.remove (x) sẽ chỉ xóa phiên bản đầu tiên của x được tìm thấy.
Nathan Garabedian

Ok, sau đó tôi nhận được nó. Trong trường hợp đó, chỉ cần sử dụng breakthay vì continuesẽ làm những gì bạn muốn, phải không? :-)
Veky

Vâng, để hiệu quả và rõ ràng, có lẽ bạn muốn sử dụng break thay vì tiếp tục trong các ví dụ này. :)
Nathan Garabedian

2

Hãy thử sử dụng một máy phát vô hạn.

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

Bằng cách sử dụng một chức năng:

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

Hãy thử chạy các mã trên bằng cách bình luận returnlà tốt.

Không sử dụng bất kỳ chức năng nào:

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

Bây giờ, hãy chạy các mã ở trên như trước và sau đó thử chạy bằng cách nhận xét từng dòng chứa breakmột dòng từ dưới lên.


2

Một cách dễ dàng để biến nhiều vòng lặp thành một vòng lặp đơn, có thể phá vỡ là sử dụng 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!

Bạn phải lập chỉ mục vào các đối tượng của mình, trái ngược với việc có thể lặp lại thông qua các giá trị một cách rõ ràng, nhưng ít nhất trong các trường hợp đơn giản, nó dường như đơn giản hơn khoảng 2-20 lần so với hầu hết các câu trả lời được đề xuất.


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

có lẽ mẹo nhỏ như dưới đây sẽ làm nếu không thích tái cấu trúc thành chức năng

đã thêm 1 biến break_level để kiểm soát điều kiện vòng lặp while

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

Bạn có thể định nghĩa một biến (ví dụ break_statement ), sau đó thay đổi nó thành một giá trị khác khi điều kiện hai ngắt xảy ra và sử dụng nó trong câu lệnh if để ngắt từ vòng lặp thứ hai.

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

Điểm tốt, tuy nhiên ở mỗi cấp trên mức quan tâm bên trong của chúng tôi, chúng tôi sẽ cần quét biến đó. Cảm thấy thực sự tồi tệ khi ngôn ngữ không có hướng dẫn GoTo, hiệu suất khôn ngoan.
Anatoly Alekseev

1

Tôi muốn nhắc bạn rằng các hàm trong Python có thể được tạo ngay giữa mã và có thể truy cập các biến xung quanh một cách trong suốt để đọc và với nonlocalhoặc globalkhai báo để viết.

Vì vậy, bạn có thể sử dụng một chức năng như một "cấu trúc điều khiển có thể phá vỡ", xác định địa điểm bạn muốn quay lại:

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

Giải pháp theo 2 cách

Với một ví dụ: Hai ma trận này có bằng nhau không?
matrix1 và matrix2 có cùng kích thước, n, 2 ma trận thay thế.

Giải pháp đầu tiên , không có chức năng

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

Giải pháp thứ hai , với chức năng
Đây là giải pháp cuối cùng cho trường hợp của tôi

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

Chúc một ngày tốt lành!


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

Hy vọng điều này sẽ giúp:

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

Đây là một triển khai có vẻ hoạt động:

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)

Hạn chế duy nhất là bạn phải xác định break_trước các vòng lặp.


0

Không có cách nào để làm điều này từ cấp độ ngôn ngữ. Một số ngôn ngữ có goto, một số ngôn ngữ khác có một cuộc tranh luận, nhưng python thì không.

Các tùy chọn tốt nhất là:

  1. Đặt cờ được kiểm tra bởi vòng lặp bên ngoài hoặc đặt điều kiện vòng lặp bên ngoài.

  2. Đặt vòng lặp trong một hàm và sử dụng return để thoát ra khỏi tất cả các vòng lặp cùng một lúc.

  3. Cải cách logic của bạn.

Tín dụng cho Vivek Nagarajan, Lập trình viên từ năm 1987


Sử dụng chức năng

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

Sử dụng cờ

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

Tương tự như trước đây, nhưng nhỏ gọn hơn. (Booleans chỉ là số)

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
Điều này trông khá xấu xí và làm cho mã khó hiểu hơn so với trước đây. Ngoài ra, đó là sai. Nó bỏ lỡ việc thực sự kiểm tra xem đầu vào có được chấp nhận hay không và sau 1 vòng lặp.
Eric

-3

Vì câu hỏi này đã trở thành một câu hỏi tiêu chuẩn để xâm nhập vào một vòng lặp cụ thể, tôi muốn đưa ra câu trả lời của mình với ví dụ sử dụng Exception .

Mặc dù tồn tại không có nhãn có tên là phá vỡ vòng lặp trong cấu trúc lặp nhiều lần, chúng ta có thể sử dụng Ngoại lệ do Người dùng xác định để đột nhập vào một vòng lặp cụ thể mà chúng ta chọn. Xem xét ví dụ sau trong đó cho phép chúng tôi in tất cả các số có tối đa 4 chữ số trong hệ thống đánh số cơ sở 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

Khi chúng tôi in đầu ra, chúng tôi sẽ không bao giờ nhận được bất kỳ giá trị nào có vị trí đơn vị là 4. Trong trường hợp đó, chúng tôi không thoát khỏi bất kỳ vòng lặp nào khi BreakLoop(4)được nâng lên và bắt trong cùng một vòng lặp. Tương tự, bất cứ khi nào mười vị trí có 3, chúng tôi sẽ chia thành vòng lặp thứ ba bằng cách sử dụng BreakLoop(3). Bất cứ khi nào hàng trăm địa điểm có 5, chúng tôi sẽ chia thành vòng lặp thứ hai bằng cách sử dụngBreakLoop(2) và khi hàng nghìn vị trí có 2, chúng ta sẽ chia thành vòng lặp thứ nhất bằng cách sử dụngBreakLoop(1) .

Nói tóm lại, hãy nâng Ngoại lệ của bạn (được xây dựng hoặc do người dùng xác định) vào các vòng bên trong và bắt nó trong vòng lặp từ nơi bạn muốn tiếp tục điều khiển của mình. Nếu bạn muốn thoát khỏi tất cả các vòng lặp, hãy bắt Ngoại lệ bên ngoài tất cả các vòng lặp. (Tôi đã không hiển thị trường hợp này trong ví dụ).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.