Về việc bắt bất kỳ ngoại lệ nào


696

Làm thế nào tôi có thể viết một try/ exceptkhối bắt tất cả các ngoại lệ?


4
Trong hầu hết các trường hợp, có lẽ bạn đang làm sai nếu bạn đang cố bắt bất kỳ ngoại lệ nào. Ý tôi là bạn có thể đơn giản viết sai một cái gì đó trong mã của bạn và thậm chí bạn sẽ không biết về nó. Đó là một thực hành tốt để nắm bắt các ngoại lệ cụ thể.
vwvolodya

12
Nói chính xác hơn, nắm bắt tất cả các ngoại lệ có thể chỉ là một vấn đề nếu chúng bị bắt âm thầm. Thật khó để nghĩ nơi nào khác phương pháp này phù hợp, ngoài nơi thông báo lỗi bị bắt được in sys.stderrvà có thể được ghi lại. Đó là một ngoại lệ hoàn toàn hợp lệ và phổ biến.
Evgeni Sergeev

bạn đã thử try: whatever() except Exception as e: exp_capture() chưa?
Charlie Parker

Câu trả lời:


564

Bạn có thể nhưng có lẽ bạn không nên:

try:
    do_something()
except:
    print "Caught it!"

Tuy nhiên, điều này cũng sẽ bắt gặp các ngoại lệ như KeyboardInterruptvà bạn thường không muốn điều đó, phải không? Trừ khi bạn nêu lại ngoại lệ ngay lập tức - xem ví dụ sau từ các tài liệu :

try:
    f = open('myfile.txt')
    s = f.readline()
    i = int(s.strip())
except IOError as (errno, strerror):
    print "I/O error({0}): {1}".format(errno, strerror)
except ValueError:
    print "Could not convert data to an integer."
except:
    print "Unexpected error:", sys.exc_info()[0]
    raise

30
Cách giải quyết có thể có: effbot.org/zone/stool-exceptions-keyboardinterrupt.htmlm
Mikel

15
Tuyên bố cuối cùng của bạn là không đúng sự thật, bạn cần phải nói rõ ràng except Exception:ngoại trừ bạn có ở đó cũng sẽ bắt được những câu hỏi BaseException.
Pykler

7
Bạn thực sự nên in ra stderr.
nyuszika7h

41
Tôi rất rất không đồng ý với tuyên bố, "không nên." Bạn nên làm điều đó một cách tiết kiệm. Đôi khi bạn giao dịch với các thư viện của bên thứ ba (đôi khi được tải động !!) đã phát điên hoàn toàn với các ngoại lệ và theo dõi tất cả chúng có thể là một nhiệm vụ rất đau đớn và nếu bạn bỏ lỡ chỉ một, bạn có một điều rất rất lỗi đau đớn lớn trong hệ thống của bạn. Điều đó đang được nói, thật tốt khi theo dõi càng nhiều càng tốt và xử lý chúng một cách thích hợp và sau đó có một bản sao lưu tất cả cho những người bạn bỏ lỡ.
Blaze

26
Điều tôi cũng thấy kỳ lạ là trong một ngôn ngữ gõ vịt nơi bạn không khai báo các biến thể hiện, đột nhiên rất lo lắng về việc không gõ tất cả các ngoại lệ của bạn. Hừm!
Blaze

834

Ngoài một except:mệnh đề trần (mà như những người khác đã nói bạn không nên sử dụng), bạn có thể chỉ cần nắm bắt Exception:

import traceback
import logging

try:
    whatever()
except Exception as e:
    logging.error(traceback.format_exc())
    # Logs the error appropriately. 

Thông thường bạn sẽ chỉ bao giờ xem xét việc này ở cấp độ ngoài cùng của mã của mình nếu ví dụ bạn muốn xử lý bất kỳ trường hợp ngoại lệ nào khác trước khi chấm dứt.

Ưu điểm của except Exceptionviệc trần trụi exceptlà có một vài trường hợp ngoại lệ mà nó sẽ không nắm bắt được, rõ ràng nhất KeyboardInterruptSystemExit: nếu bạn bắt và nuốt chúng thì bạn có thể khiến mọi người khó thoát khỏi kịch bản của mình.


Tôi đã có một điều tương tự trong đầu, nhưng chúng là một bất lợi, giả sử chúng là hai lỗi khi một lần bị bắt và ngoại trừ bạn chỉ in bạn sẽ thoát khỏi khối thử và bạn sẽ không bao giờ biết lỗi thứ hai .. .

6
Đối với bất cứ ai tự hỏi, hoàn toàn trái với dự đoán của tôi, điều này vẫn sẽ bắt được những thứ không phải là ngoại lệ như ints, ít nhất là trong python 2.x.
Joseph Garvin

5
@JosephGarvin, điều đó không chính xác, nghĩa là điều này sẽ không bắt được "trường hợp ngoại lệ" không phân lớp Exception. Lưu ý rằng không thể đưa ra intmột ngoại lệ và cố gắng làm như vậy sẽ tạo ra một TypeErrorngoại lệ, đó là điều sẽ bị bắt bởi except Exceptionmệnh đề kèm theo trong trường hợp như vậy. Mặt khác, một lớp kiểu cũ có thể được nâng lên và đủ điều kiện là "không ngoại lệ" không phải là lớp con Exception- điều này sẽ bị bắt bởi một exceptmệnh đề trần nhưng không phải bởi một except Exceptionmệnh đề.
Yoel

4
@JosephGarvin kiểm tra blog entry này: chris-lamb.co.uk/posts/no-one-expects-string-literal-exception Tôi với @Yoel một ngày này, thử nghiệm của bạn chỉ cần đeo mặt nạ cácTypeError
Duncan

2
@CharlieParker không có gì sai khi bắt chúng nếu đó là điều bạn muốn nhưng chủ yếu là không. Gọi điện sys.exit()thường có nghĩa là bạn mong muốn ứng dụng chấm dứt nhưng nếu bạn bắt gặp SystemExit thì nó sẽ không. Tương tự như vậy nếu bạn nhấn control-C trên tập lệnh đang chạy (Ctrl-break trên windows), bạn hy vọng chương trình sẽ dừng, không bắt lỗi và tiếp tục. Nhưng bạn có thể bắt một trong hai hoặc cả hai thứ này nếu bạn muốn dọn dẹp trước khi tồn tại.
Duncan

100

Bạn có thể làm điều này để xử lý các trường hợp ngoại lệ chung

try:
    a = 2/0
except Exception as e:
    print e.__doc__
    print e.message

8
Điều này có thể không bắt được tất cả các ngoại lệ, vì lớp cơ sở cho tất cả các ngoại lệ là BaseException và tôi đã gặp mã sản xuất không thuộc họ lớp Exception. Xem docs.python.org/3/l Library / ' để biết chi tiết về điều này.
DDay

4
Điều này không bắt tất cả các ngoại lệ.
Andy_A̷n̷d̷y̷

6
Về mặt kỹ thuật, nó nên nắm bắt tất cả các ngoại lệ không có hệ thống. Từ các tài liệu @DDay được liên kết: " ngoại lệ BaseException: Lớp cơ sở cho tất cả các ngoại lệ tích hợp. Nó không có nghĩa là được kế thừa trực tiếp bởi các lớp do người dùng định nghĩa (vì vậy, hãy sử dụng Ngoại lệ)." Trừ khi bạn đang làm việc với mã mà bỏ qua điều này, hoặc bạn cần nắm bắt các ngoại lệ thoát khỏi hệ thống, thì ở trên sẽ được sử dụng.
Peter Cassetta

@PeterCassetta khi nào người ta muốn bắt ngoại lệ hệ thống? Có vẻ như chủ đề chung trong câu hỏi mà chúng tôi không muốn nắm bắt những điều này, nhưng tôi không hiểu tại sao. Tại sao không thường xuyên?
Charlie Parker

68

Để nắm bắt tất cả các ngoại lệ có thể, bắt BaseException . Nó nằm trên hệ thống phân cấp Exception:

Python 3: https://docs.python.org/3.5/l Library / exceptions.html # exception-hierarchy

Python 2.7: https://docs.python.org/2.7/l Library / exceptions.html # exception-harcharchy

try:
    something()
except BaseException as error:
    print('An exception occurred: {}'.format(error))

Nhưng như những người khác đã đề cập, bạn thường sẽ không cần điều này, chỉ cho các trường hợp cụ thể.


1
Có muốn lưu tiến trình của một công việc dài hạn sau khi nhấn Ctrl-C có bất thường không?
BallpointBen

54

Ví dụ rất đơn giản, tương tự như ví dụ được tìm thấy ở đây:

http://docs.python.org/tutorial/errors.html#defining-clean-up-ilities

Nếu bạn đang cố bắt TẤT CẢ các ngoại lệ, thì hãy đặt tất cả mã của bạn vào câu lệnh "thử:", thay cho 'in "Thực hiện một hành động có thể ném ngoại lệ."'.

try:
    print "Performing an action which may throw an exception."
except Exception, error:
    print "An exception was thrown!"
    print str(error)
else:
    print "Everything looks great!"
finally:
    print "Finally is called directly after executing the try statement whether an exception is thrown or not."

Trong ví dụ trên, bạn sẽ thấy đầu ra theo thứ tự này:

1) Thực hiện một hành động có thể ném một ngoại lệ.

2) Cuối cùng được gọi trực tiếp sau khi thực hiện câu lệnh thử xem có ngoại lệ được ném hay không.

3) "Một ngoại lệ đã được ném!" hoặc "Mọi thứ trông thật tuyệt!" tùy thuộc vào việc một ngoại lệ đã được ném.

Hi vọng điêu nay co ich!


26

Có nhiều cách để làm điều này cụ thể với Python 3.0 trở lên

Cách tiếp cận 1

Đây là cách tiếp cận đơn giản nhưng không được khuyến nghị vì bạn sẽ không biết chính xác dòng mã nào thực sự ném ngoại lệ:

def bad_method():
    try:
        sqrt = 0**-1
    except Exception as e:
        print(e)

bad_method()

Cách tiếp cận 2

Cách tiếp cận này được khuyến nghị vì nó cung cấp chi tiết hơn về từng ngoại lệ. Nó bao gồm:

  • Số dòng cho mã của bạn
  • Tên tệp
  • Các lỗi thực tế theo cách dài dòng hơn

Hạn chế duy nhất là tracback cần phải được nhập khẩu.

import traceback

def bad_method():
    try:
        sqrt = 0**-1
    except Exception:
        print(traceback.print_exc())

bad_method()

21

Tôi vừa tìm ra mẹo nhỏ này để kiểm tra nếu tên ngoại lệ trong Python 2.7. Đôi khi tôi đã xử lý các trường hợp ngoại lệ cụ thể trong mã, vì vậy tôi cần một bài kiểm tra để xem tên đó có nằm trong danh sách các trường hợp ngoại lệ được xử lý hay không.

try:
    raise IndexError #as test error
except Exception as e:
    excepName = type(e).__name__ # returns the name of the exception

2
try:
    whatever()
except:
    # this will catch any exception or error

Điều đáng nói là đây không phải là mã Python thích hợp. Điều này cũng sẽ bắt được nhiều lỗi mà bạn có thể không muốn bắt.


chỉ sử dụng ngoại trừ không lưu trữ tất cả các ngoại lệ như được đề cập trong một số câu trả lời khác. Bạn phải sử dụng BaseException cho mục đích này nhưng như bạn đã nói, không ai nên nắm bắt tất cả các ngoại lệ như thế này. Tôi đoán sẽ ổn khi bắt đầu nếu mục tiêu là thêm chi tiết hơn ngoại trừ trong quá trình phát triển nhưng tôi không nghĩ nó sẽ ...
Pyglouthon
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.