2016-02-19 13 views
17

xem xét:lệnh break trong khối finally nuốt ngoại lệ

def raiseMe(text="Test error"): 
    raise Exception(text) 

def break_in_finally_test(): 
    for i in range(5): 
     if i==2: 
      try: 
       raiseMe() 
      except: 
       raise 
      else: 
       print "succeeded!" 
      finally: 
       print "testing this!" 
       break 

if __name__=='__main__': 
    break_in_finally_test() 

tôi mong đợi để xem Exception("Test error") được nâng lên, nhưng thay vì chỉ "thử nghiệm này" được in ra. Ý định, tất nhiên, là để gọi raiseMe() chỉ một lần, không có vấn đề nếu chúng ta thành công hay không - nhưng nếu nó làm tăng một ngoại lệ, tôi đã muốn thấy điều đó!

Tại sao phá vỡ ngoại lệ mà tôi đã nêu rõ?

+0

Tôi không chắc tại sao chính xác điều đó xảy ra (và thấy nó hơi ngạc nhiên), nhưng bạn có thể đột nhập bên trong 'else' thay vào đó, vì trong trường hợp ngoại lệ, nó sẽ thoát khỏi vòng lặp. – bereal

+0

Tôi có thể hiểu làm thế nào 'return' trong công việc cuối cùng, nhưng với' break' nó chỉ là lạ. Ví dụ của bạn không bao gồm điều này, nhưng phương pháp thậm chí sẽ tiếp tục thực hiện sau khi vòng lặp! –

Trả lời

28

Từ https://docs.python.org/2.7/reference/compound_stmts.html#finally:

Nếu cuối cùng có mặt, nó xác định một handler ‘dọn dẹp’. Mệnh đề try được thực thi là
, bao gồm bất kỳ mệnh đề ngoại trừ và mệnh đề nào khác. Nếu ngoại lệ xảy ra trong
bất kỳ mệnh đề nào và không được xử lý, ngoại lệ sẽ được lưu tạm thời.
Điều khoản cuối cùng được thực hiện. Nếu có một ngoại lệ đã lưu, nó được
tăng lại ở cuối điều khoản cuối cùng. Nếu mệnh đề cuối cùng làm tăng
ngoại lệ khác hoặc thực hiện một sự trở lại hoặc phá vỡ tuyên bố, lưu
ngoại lệ được bỏ đi

này cũng phản ánh hành vi dự kiến ​​từ báo cáo kết quả try...finally trước PEP341:

Đây là cách một thử ngoại trừ cuối cùng khối trông giống như trước PEP341:

try: 
    try: 
     raiseMe() 
    except: 
     raise 
finally: 
    #here is where cleanup is supposed to happen before raising error 
    break 
    #after finally code: raise error 

Khi việc tăng lỗi không bao giờ xảy ra trong finally chặn nó không bao giờ thực sự được nâng lên.

Để duy trì tính tương thích ngược với các phiên bản python 2.4 và ít hơn nó phải được thực hiện theo cách này.

+1

Ok, vì vậy nó đã được ghi lại. Nhưng tôi phải nói rằng tôi vẫn thấy hành vi này thực sự đáng ngạc nhiên (không giống như hầu hết các hành vi python, mà thường là rất trực quan). Cảm giác của tôi là Ngoại lệ nên "át chủ bài" (s) hoặc phá vỡ ... – TimO

+0

@TIMO Tôi đồng ý. Tôi tự hỏi nếu có lẽ điều này đã không được thực hiện theo cách này bởi vì họ sẽ không phải ghi đè lên hành vi phá vỡ cho loại đặc biệt của khối. –

1

I nghĩ rằng khi phản ánh rằng đó là do thực tế là ngắt thực sự tăng một StopIteration để "phá vỡ" ra khỏi vòng lặp for. Điều này thực sự không phải là rất trực quan và không được tài liệu đặc biệt tốt (không được đề cập trên ví dụ 1). Có lẽ ai đó có thể xác nhận/giải thích nó tốt hơn?

+0

Đây thực sự là trường hợp, hoặc chỉ là một dự đoán? Nếu điều này là như vậy, sau đó tôi không nên có thể bắt ngoại lệ StopIteration gây ra bởi phá vỡ trong vòng lặp? Việc nâng cấp StopIteration theo cách thủ công trong vòng lặp for cũng không có tác dụng tương tự. –

+0

@tobias_k Đó là - có lẽ là sai - đoán. Các tài liệu giải thích nó - xem câu trả lời được chấp nhận. – TimO

5

Từ các tài liệu Error Handling Docs:

Một khoản cuối cùng luôn được thực hiện trước khi rời khỏi câu lệnh try, cho dù một ngoại lệ đã xảy ra hay không.

Ngoại lệ của bạn không bao giờ được nâng lên vì bạn đã phá vỡ trước khi câu lệnh thử được đánh giá đầy đủ.

Các vấn đề liên quan