Python nâng cao từ cách sử dụng


196

Sự khác biệt giữa raiseraise fromtrong Python là gì?

try:
    raise ValueError
except Exception as e:
    raise IndexError

mang lại

Traceback (most recent call last):
  File "tmp.py", line 2, in <module>
    raise ValueError
ValueError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "tmp.py", line 4, in <module>
    raise IndexError
IndexError

try:
    raise ValueError
except Exception as e:
    raise IndexError from e

mang lại

Traceback (most recent call last):
  File "tmp.py", line 2, in <module>
    raise ValueError
ValueError

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "tmp.py", line 4, in <module>
    raise IndexError from e
IndexError

9
Bạn đã đọc PEP-3134 chưa?
jonrsharpe

4
Bây giờ sử dụng raise IndexError from None, nói.
Martijn Pieters

11
Heh. raise IndexError from Falsetăng a TypeError, không phải an IndexError. Làm cho ngày của tôi.
Nhà vật lý điên


Không chắc đây có phải là nơi thích hợp để đề cập đến nó không, nhưng với bất kỳ ai sử dụng Spyder: Toàn bộ cấu trúc này không hoạt động ở đó. Đây là một vấn đề trong hơn 3 năm nay ( github.com/spyder-ide/spyder/issues/2943 ), nhưng dường như họ nghĩ rằng không cần phải có ngoại lệ.
Emil Bode

Câu trả lời:


227

Sự khác biệt là khi bạn sử dụng from, __cause__thuộc tính được đặt và thông báo cho biết ngoại lệ được gây ra trực tiếp bởi . Nếu bạn bỏ qua fromthì không __cause__được đặt, nhưng __context__thuộc tính cũng có thể được đặt và truy nguyên sau đó hiển thị bối cảnh như trong khi xử lý một cái gì đó khác đã xảy ra .

Đặt điều __context__xảy ra nếu bạn sử dụng raisetrong một trình xử lý ngoại lệ; nếu bạn sử dụng raisebất cứ nơi nào khác thì không __context__được đặt.

Nếu a __cause__được đặt, một __suppress_context__ = Truecờ cũng được đặt trên ngoại lệ; khi __suppress_context__được đặt thành True, __context__sẽ bị bỏ qua khi in dấu vết.

Khi nâng lên từ một trình xử lý ngoại lệ mà bạn không muốn hiển thị ngữ cảnh (không muốn trong khi xử lý một thông báo ngoại lệ khác xảy ra ), sau đó sử dụng raise ... from Noneđể đặt __suppress_context__thànhTrue .

Nói cách khác, Python đặt bối cảnh cho các trường hợp ngoại lệ để bạn có thể hướng nội nơi một ngoại lệ được đưa ra, cho bạn biết nếu một ngoại lệ khác được thay thế bởi nó. Bạn cũng có thể thêm một nguyên nhân vào một ngoại lệ, làm cho dấu vết rõ ràng về ngoại lệ khác (sử dụng từ ngữ khác) và bối cảnh bị bỏ qua (nhưng vẫn có thể bị thâm nhập khi gỡ lỗi). Sử dụngraise ... from None cho phép bạn ngăn chặn bối cảnh được in.

Xem thông raisetin tuyên bố :

Các fromkhoản được sử dụng cho ngoại lệ chaining: nếu được, thứ hai biểu hiện phải khác lớp ngoại lệ hoặc dụ, sau đó sẽ được gắn vào ngoại lệ huy động là __cause__thuộc tính (đó là ghi). Nếu ngoại lệ nâng lên không được xử lý, cả hai ngoại lệ sẽ được in:

>>> try:
...     print(1 / 0)
... except Exception as exc:
...     raise RuntimeError("Something bad happened") from exc
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ZeroDivisionError: int division or modulo by zero

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
RuntimeError: Something bad happened

Một cơ chế tương tự hoạt động ngầm nếu một ngoại lệ được đưa ra bên trong một trình xử lý ngoại lệ hoặc một finallymệnh đề: ngoại lệ trước đó được đính kèm dưới dạng __context__thuộc tính của ngoại lệ mới :

>>> try:
...     print(1 / 0)
... except:
...     raise RuntimeError("Something bad happened")
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ZeroDivisionError: int division or modulo by zero

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
RuntimeError: Something bad happened

Đồng thời xem tài liệu Ngoại lệ tích hợp để biết chi tiết về ngữ cảnh và gây ra thông tin kèm theo ngoại lệ.


11
Có bất kỳ lý do để rõ ràng xâu chuỗi các ngoại lệ bằng cách sử dụng from__cause__thay cho ẩn __context__? Có trường hợp nào người ta sẽ đính kèm một ngoại lệ khác với trường hợp bị bắt bởi exceptkhông?
darkfeline

13
@darkfeline: Hãy nói rằng API cơ sở dữ liệu của bạn hỗ trợ mở cơ sở dữ liệu từ nhiều nguồn khác nhau, bao gồm cả web và đĩa. API của bạn sẽ luôn tăng DatabaseErrornếu mở cơ sở dữ liệu không thành công. Nhưng nếu lỗi là IOErrordo tệp không mở được hoặc HTTPErrordo URL không hoạt động thì đó là bối cảnh bạn muốn đưa vào một cách rõ ràng, vì vậy nhà phát triển sử dụng API có thể gỡ lỗi tại sao lại như vậy. Ngay lúc đó bạn sử dụng raise DatabaseError from original_exception.
Martijn Pieters

4
@darkfeline: Nếu nhà phát triển được gói việc sử dụng các API cơ sở dữ liệu API của riêng mình và muốn truyền lại rằng IOErrorhoặc HTTPErrorvào họ tiêu dùng, sau đó họ sẽ phải sử dụng raise NewException from databaseexception.__cause__, bây giờ sử dụng một ngoại lệ khác nhau từ DatabaseExceptionđó họ mới bắt được.
Martijn Pieters

2
@ dan3: không, không có. Chuỗi ngoại lệ hoàn toàn là một tính năng của Python 3.
Martijn Pieters

5
@ laike9m: ý bạn là khi bạn đang xử lý ngoại lệ foovà muốn đưa ra một ngoại lệ mớibar ? Sau đó, bạn có thể sử dụng raise bar from foovà có trạng thái Python foo trực tiếp gây rabar . Nếu bạn không sử dụng from foo, thì Python vẫn sẽ in cả hai, nhưng nói rằng trong quá trình xử lý foo, barđã được đưa ra , Thông báo khác nhau, nhằm đánh dấu một lỗi có thể xảy ra trong xử lý lỗi.
Martijn Pieters
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.