Hành vi kỳ lạ Thử-Ngoại trừ-Khác-Cuối cùng với câu lệnh Return


88

Đây là một số mã đang hoạt động kỳ lạ. Đây là phiên bản đơn giản hóa của hành vi mà tôi đã viết. Điều này vẫn sẽ chứng tỏ hành vi kỳ lạ và tôi đã có một số câu hỏi cụ thể về lý do tại sao điều này lại xảy ra.

Tôi đang sử dụng Python 2.6.6 trên Windows 7.

def demo1():
    try:
        raise RuntimeError,"To Force Issue"
    except:
        return 1
    else:
        return 2
    finally:
        return 3

def demo2():
    try:
        try:
            raise RuntimeError,"To Force Issue"
        except:
            return 1
        else:
            return 2
        finally:
            return 3
    except:
        print 4
    else:
        print 5
    finally:
        print 6

Các kết quả:

>>> print demo1()
3
>>> print demo2()
6
3
  • Tại sao bản demo một trả về 3 thay vì 1?
  • Tại sao bản demo hai in 6 thay vì in 6 w / 4 hoặc 5?

Câu trả lời:


124

Bởi vì các finallycâu lệnh được đảm bảo sẽ được thực thi (tốt, giả sử không bị mất điện hoặc bất kỳ thứ gì nằm ngoài tầm kiểm soát của Python). Điều này có nghĩa là trước khi hàm có thể trả về, nó phải chạy khối cuối cùng, khối này trả về một giá trị khác.

Các Python tài liệu nhà nước:

Khi một câu lệnh return, break hoặc continue được thực thi trong bộ lệnh try của câu lệnh try… last, mệnh đề cuối cùng cũng được thực thi 'trên đường ra'.

Giá trị trả về của một hàm được xác định bởi câu lệnh trả về cuối cùng được thực thi. Vì mệnh đề cuối cùng luôn thực thi, một câu lệnh trả về được thực thi trong mệnh đề cuối cùng sẽ luôn là câu lệnh cuối cùng được thực thi:

Điều này có nghĩa là khi bạn cố gắng trả về, finallykhối sẽ được gọi, trả về giá trị của nó, thay vì giá trị mà bạn đã có.


4
Tại sao số 5 không in trong ví dụ thứ hai? tôi nghĩ điều này vẫn chưa được giải thích rõ. một trong những sự trở lại được trả lời tốt nhưng tại sao doesnt 5 trong ví dụ thứ hai in
Joran Beasley

5
oh tôi nghĩ rằng tôi figured it out sự trở lại trong lần thử đầu tiên làm cho nó nhảy ngay cho bên ngoài cuối cùng
Joran Beasley

2
Chính xác, vì finallycác khối luôn chạy.
Gareth Latty

2
Trong bản demo thứ hai, tại sao nó thực hiện lệnh lồng nhau cuối cùng, kick ra bên ngoài cuối cùng rồi quay lại vào lồng nhau cuối cùng để kết thúc việc trả về thay vì chỉ trả lại None từ bên ngoài?
Kyle Owens

1
Bởi vì khi returncâu lệnh được gọi, Python sẽ kiểm tra bất kỳ finallymệnh đề mở nào cần được thực thi (xem phần trích dẫn ở trên).
Gareth Latty

6

Thứ tự thực hiện là:

  1. thử khối tất cả hoàn thành bình thường -> khối cuối cùng -> chức năng kết thúc
  2. thử khối chạy và vào ngoại lệ A -> cuối cùng khối -> chức năng kết thúc
  3. thử khối tạo giá trị trả về và gọi trả về -> cuối cùng là khối -> giá trị trả về bật lên -> hàm kết thúc

Vì vậy, bất kỳ trả lại nào trong khối cuối cùng sẽ kết thúc các bước trước.

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.