Cách nhận thông báo ngoại lệ bằng Python đúng cách


97

Cách tốt nhất để nhận thông báo ngoại lệ từ các thành phần của thư viện chuẩn trong Python là gì?

Tôi nhận thấy rằng trong một số trường hợp, bạn có thể lấy nó qua messagetrường như sau:

try:
  pass
except Exception as ex:
  print(ex.message)

nhưng trong một số trường hợp (ví dụ: trong trường hợp lỗi ổ cắm) bạn phải làm như sau:

try:
  pass
except socket.error as ex:
  print(ex)

Tôi tự hỏi có cách tiêu chuẩn nào để giải quyết hầu hết các tình huống này không?


1
Bạn đang kết hợp hai thứ khác nhau - except Foo as bar:giống nhau except Foo, bar:(ngoại trừ cái cũ mới hơn và sẽ tiếp tục hoạt động trong 3.x), cho dù lỗi đi kèm với một messagethuộc tính hay không là riêng biệt.
jonrsharpe

1
@FrozenHeart Bạn đang hỏi liệu truy cập .messagelỗi có phải là cách chuẩn hay không?
Anand S Kumar

Ví dụ thứ hai của mình với print(msg)chỉ một phím tắt choprint(str(msg))
Salo

@Anand S Kumar Yep. Nó sẽ hoạt động trong mọi trường hợp?
FrozenHeart

4
Tôi tin rằng truy cập messagekhông được dùng nữa.
Jonathon Reinhart

Câu trả lời:


94

Nếu bạn xem tài liệu về các lỗi tích hợp , bạn sẽ thấy rằng hầu hết Exceptioncác lớp đều gán đối số đầu tiên của chúng làm messagethuộc tính. Không phải tất cả chúng đều như vậy.

Đáng chú ý, EnvironmentError(với các lớp con IOErrorOSError) có đối số đầu tiên là, đối số errnothứ hai strerror. Không có message... strerrorgần giống với những gì thường sẽ là a message.

Nói chung hơn, các lớp con của Exceptioncó thể làm bất cứ điều gì chúng muốn. Chúng có thể có hoặc không có messagethuộc tính. Các tích hợp trong tương lai Exceptioncó thể không có messagethuộc tính. Bất kỳ Exceptionlớp con nào được nhập từ thư viện của bên thứ ba hoặc mã người dùng có thể không có messagethuộc tính.

Tôi nghĩ rằng cách thích hợp để xử lý điều này là xác định các Exceptionlớp con cụ thể mà bạn muốn nắm bắt, sau đó chỉ bắt những người đó thay vì mọi thứ bằng một except Exception, sau đó sử dụng bất kỳ thuộc tính nào mà lớp con cụ thể xác định theo cách bạn muốn.

Nếu bạn phải làm printđiều gì đó, tôi nghĩ rằng việc in Exceptionbản thân nó có nhiều khả năng làm những gì bạn muốn, cho dù nó có messagethuộc tính hay không.

Bạn cũng có thể kiểm tra thuộc tính message nếu bạn muốn, như thế này, nhưng tôi sẽ không thực sự đề xuất nó vì nó có vẻ lộn xộn:

try:
    pass
except Exception as e:
    # Just print(e) is cleaner and more likely what you want,
    # but if you insist on printing message specifically whenever possible...
    if hasattr(e, 'message'):
        print(e.message)
    else:
        print(e)

Cảm ơn vì câu trả lời. Có lý do cụ thể nào để sử dụng str(ex)thay vì chỉ ex?
FrozenHeart

3
@FrozenHeart - print()tự động gọi str()cho bạn. Không có lý do gì để tự gọi nó theo cách thủ công, mặc dù nó vô hại vì việc gọi str()trên một chuỗi sẽ chỉ trả về chính chuỗi đó.
ArtOfWarfare vào

1
@ArtOfWarfare Tôi nghĩ rằng có thể có vấn đề với str()nếu loại tin nhắn unicode.
kratenko

35

Để cải thiện câu trả lời do @artofwarfare cung cấp , đây là điều tôi coi là một cách gọn gàng hơn để kiểm tra messagethuộc tính và in nó hoặc in Exceptionđối tượng dưới dạng dự phòng.

try:
    pass 
except Exception as e:
    print getattr(e, 'message', repr(e))

Cuộc gọi tới reprlà tùy chọn, nhưng tôi thấy nó cần thiết trong một số trường hợp sử dụng.


Cập nhật # 1:

Sau nhận xét của @MadPhysicist , đây là bằng chứng về lý do tại sao việc gọi đến reprcó thể cần thiết. Hãy thử chạy mã sau trong trình thông dịch của bạn:

try:
    raise Exception 
except Exception as e:
    print(getattr(e, 'message', repr(e)))
    print(getattr(e, 'message', str(e)))

Cập nhật # 2:

Đây là bản demo với các chi tiết cụ thể cho Python 2.7 và 3.5: https://gist.github.com/takwas/3b7a6edddef783f2abddffda1439f533


1
getattrném một ngoại lệ nếu đối tượng được truyền vào không có thuộc tính được yêu cầu. Nếu bạn muốn làm một cái gì đó như thế, tôi nghĩ rằng bạn nên sử dụng đối số thứ ba tùy chọn cho getattr, như thế này: print getattr(e, 'message', e). Tốt hơn đáng kể so với những gì tôi đã làm. Một lựa chọn khác sẽ là print(e.message if hasattr(e, 'message') else e).
ArtOfWarfare

2
Bạn gần như chắc chắn sẽ muốn strthay vì repr.
Mad Physicist,

2
So với str, reprchỉ cần thêm tên lớp. Thay vì sử dụng repr, tôi đề xuất sử dụng print('{e.__class__.__name__}: {e}'.format(e=e)). Đầu ra in rõ ràng hơn và tuân theo đầu ra của chính nó.
kadee

1
Dựa trên những điều trên, tôi thấy điều hữu ích nhất đối với tôi'{e.__class__.__module__}.{e.__class__.__name__}: {e}'
shadi

1
Cảm ơn!! repr(e)hiện tại là giải pháp duy nhất giúp tôi in ít nhất một lượng thông tin tối thiểu về một lỗi tôi mắc phải trong một số trường hợp cụ thể. repr(e)sản lượng KeyError(0,)(đó là lỗi là gì), trong khi str(e)hoặc e.messagechỉ mang lại 0hoặc không có gì tương ứng.
FlorianH

0

Tôi đã từng gặp vấn đề tương tự. Tôi nghĩ giải pháp tốt nhất là sử dụng log.exception, sẽ tự động in ra dấu vết ngăn xếp và thông báo lỗi, chẳng hạn như:

try:
    pass
    log.info('Success')
except:
    log.exception('Failed')

1
loggì? Tôi vừa thử import logtrên Python 2.7.13 và nhận được thông báo rằng không có mô-đun nào có tên đó. Đó có phải là thứ bạn đã thêm qua piphay nó đã được thêm vào phiên bản python mới hơn (Tôi biết, tôi biết, tôi cần cập nhật lên Python 3 ... Tôi sẽ làm điều đó ngay khi CentOS ngừng vận chuyển với Python 2 theo mặc định ...)
ArtOfWarfare

6
Anh ấy / Cô ấy có thể đang sử dụng mô-đun ghi nhật ký từ python và sau đó khởi tạo trình ghi nhật ký dưới dạng biến nhật ký. import logging\ nlog = logging.getLogger(__name__)
Josepas

0

Tôi cũng có cùng một vấn đề. Tìm hiểu kỹ về vấn đề này, tôi thấy rằng lớp Exception có một argsthuộc tính, thuộc tính này nắm bắt các đối số được sử dụng để tạo ngoại lệ. Nếu bạn thu hẹp các ngoại lệ mà ngoại trừ sẽ bắt vào một tập hợp con, bạn sẽ có thể xác định cách chúng được xây dựng và do đó đối số nào chứa thông báo.

try:
   # do something that may raise an AuthException
except AuthException as ex:
   if ex.args[0] == "Authentication Timeout.":
      # handle timeout
   else:
      # generic handling
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.