จับข้อความข้อยกเว้นหลาม


520
import ftplib
import urllib2
import os
import logging
logger = logging.getLogger('ftpuploader')
hdlr = logging.FileHandler('ftplog.log')
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
hdlr.setFormatter(formatter)
logger.addHandler(hdlr)
logger.setLevel(logging.INFO)
FTPADDR = "some ftp address"

def upload_to_ftp(con, filepath):
    try:
        f = open(filepath,'rb')                # file to send
        con.storbinary('STOR '+ filepath, f)         # Send the file
        f.close()                                # Close file and FTP
        logger.info('File successfully uploaded to '+ FTPADDR)
    except, e:
        logger.error('Failed to upload to ftp: '+ str(e))

ดูเหมือนจะใช้งานไม่ได้ฉันได้รับข้อผิดพลาดทางไวยากรณ์วิธีที่เหมาะสมในการทำเช่นนี้สำหรับการบันทึกข้อยกเว้นทุกประเภทลงในไฟล์คืออะไร


2
การเยื้องของคุณถูกทำลาย และละเว้นหลัง, except
Sven Marnach

3
@SvenMarnach หากคุณไม่ได้ใช้งาน,หลังจากexceptนั้นคุณจะได้รับglobal name 'e' is not definedซึ่งไม่ดีไปกว่าไวยากรณ์ที่ผิด
Val

12
@Val: ควรเป็นexcept Exception as eหรือexcept Exception, eขึ้นอยู่กับเวอร์ชันของ Python
Sven Marnach

1
อาจเป็นที่รอบ ๆ 8 คำตอบนั้น แต่เมื่อคุณเปิดไฟล์ส่วนที่ใกล้ชิดไม่ควรอยู่ในคำสั่ง try แต่ไม่ว่าจะเป็นคำสั่งสุดท้ายหรือล้อมรอบด้วย a คำสั่ง
JC Rocamonde

คำตอบ:


733

คุณต้องกำหนดประเภทของข้อยกเว้นที่คุณต้องการจับ ดังนั้นเขียนexcept Exception, e:แทนexcept, e:ข้อยกเว้นทั่วไป (ที่จะเข้าสู่ระบบอยู่แล้ว)

ความเป็นไปได้อื่นคือการเขียนลอง / ยกเว้นโค้ดด้วยวิธีนี้:

try:
    with open(filepath,'rb') as f:
        con.storbinary('STOR '+ filepath, f)
    logger.info('File successfully uploaded to '+ FTPADDR)
except Exception, e: # work on python 2.x
    logger.error('Failed to upload to ftp: '+ str(e))

ใน Python 3.x และ Python 2.x เวอร์ชันสมัยใหม่ใช้except Exception as eแทนexcept Exception, e:

try:
    with open(filepath,'rb') as f:
        con.storbinary('STOR '+ filepath, f)
    logger.info('File successfully uploaded to '+ FTPADDR)
except Exception as e: # work on python 3.x
    logger.error('Failed to upload to ftp: '+ str(e))

118
repr (e) ให้ข้อยกเว้นแก่คุณ (และสตริงข้อความ); str (e) ให้สตริงข้อความเท่านั้น
หนวดขาว

11
เป็นอีกทางเลือกหนึ่งสำหรับการบันทึกข้อยกเว้นคุณสามารถใช้logger.exception(e)แทน มันจะบันทึกข้อยกเว้นด้วยการย้อนกลับในlogging.ERRORระดับเดียวกัน
mbdevpl

1
@mbdevpl ดูเหมือนจะไม่เป็นจริง ดูเหมือนว่าจะโทรไปที่ str () ยกเว้น: ideone.com/OaCOpO
KevinOrr

6
except Exception, e:ส่งข้อผิดพลาดทางไวยากรณ์มาให้ฉันใน python 3 คาดว่าจะเกิดอะไรขึ้น
Charlie Parker

27
@CharlieParker ใน Python3 เขียนexcept Exception as e:
eumiro

282

ไม่รองรับไวยากรณ์ใน python 3 อีกต่อไปใช้สิ่งต่อไปนี้แทน

try:
    do_something()
except BaseException as e:
    logger.error('Failed to do something: ' + str(e))

2
ที่จริงแล้วคุณควรใช้ logger.error ('ล้มเหลวในการทำบางสิ่ง:% s', str (e)) ด้วยวิธีนี้หากระดับตัวบันทึกของคุณอยู่เหนือข้อผิดพลาดจะไม่ทำการแก้ไขสตริง
avyfain

7
@avyfain - คุณไม่ถูกต้อง คำสั่งlogging.error('foo %s', str(e))จะแปลงeเป็นสตริงเสมอ เพื่อให้บรรลุสิ่งที่คุณเป็นหลังจากนั้นคุณจะใช้logging.error('foo %s', e)- ดังนั้นจึงอนุญาตให้เฟรมเวิร์กการบันทึกทำ (หรือไม่ทำการแปลง)
Ron Dahlgren

1
คุณสามารถตรวจสอบได้ในงูหลาม REPL (ที่นี่ด้วย Python 3.5.2 และ ipython): ดูส่วนสำคัญของฉันที่นี่
Ron Dahlgren

2
เป็นอีกทางเลือกหนึ่งสำหรับการบันทึกข้อยกเว้นคุณสามารถใช้logger.exception(e)แทน มันจะบันทึกข้อยกเว้นด้วยการย้อนกลับในlogging.ERRORระดับเดียวกัน
mbdevpl

11
ระวังexcept BaseExceptionและexcept Exceptionไม่ได้อยู่ในระดับเดียวกัน except Exceptionทำงานใน Python3 ได้ แต่จะไม่KeyboardInterruptเป็นเช่นนั้น (ซึ่งจะสะดวกมากถ้าคุณต้องการที่จะสามารถขัดจังหวะโค้ดของคุณ!) ในขณะที่BaseExceptionจับข้อยกเว้น ดูลิงค์นี้สำหรับลำดับชั้นของข้อยกเว้น
jeannej

41

การอัปเดตสิ่งนี้เป็นสิ่งที่ง่ายกว่าสำหรับคนตัดไม้ (ใช้ได้ทั้งหลาม 2 และ 3) คุณไม่ต้องการโมดูลการติดตามกลับ

import logging

logger = logging.Logger('catch_all')

def catchEverythingInLog():
    try:
        ... do something ...
    except Exception as e:
        logger.error(e, exc_info=True)
        ... exception handling ...

นี่เป็นวิธีเก่า (แต่ก็ยังใช้ได้อยู่):

import sys, traceback

def catchEverything():
    try:
        ... some operation(s) ...
    except:
        exc_type, exc_value, exc_traceback = sys.exc_info()
        ... exception handling ...

exc_value เป็นข้อความแสดงข้อผิดพลาด


2
นี่จะเป็นวิธีที่ฉันชอบ เพียงพิมพ์สตริงจะมีประโยชน์สำหรับการบันทึกฉันคิดว่า แต่ถ้าฉันต้องการทำอะไรกับข้อมูลที่ฉันต้องการมากกว่าแค่สตริง
sulimmesh

3
คุณไม่จำเป็นต้อง 'นำเข้า traceback' ในตัวอย่างที่สองใช่ไหม
starikoff

35

มีบางกรณีที่คุณสามารถใช้e.messageหรือe.messages ได้ .. แต่มันไม่ทำงานในทุกกรณี อย่างไรก็ตามความปลอดภัยที่มากกว่าคือการใช้str (e)

try:
  ...
except Exception as e:
  print(e.message)

42
ปัญหานี้เป็นตัวอย่างเช่นถ้าคุณexcept Exception as eและeเป็นIOErrorคุณจะได้รับe.errno, e.filenameและe.strerrorแต่เห็นได้ชัดว่าไม่มีe.message(อย่างน้อยในหลาม 2.7.12) หากคุณต้องการจับข้อความแสดงข้อผิดพลาดให้ใช้str(e)เช่นเดียวกับคำตอบอื่น ๆ
epalm

@epalm จะเกิดอะไรขึ้นถ้าคุณจับ IOError ก่อน Exception?
Albert Thompson

@ HeribertoJuárezทำไมถึงจับจองกรณีพิเศษในขณะที่คุณสามารถโยนมันลงบนสตริงได้
HosseyNJF

25

ถ้าคุณต้องการให้ระดับความผิดพลาดข้อผิดพลาดและการติดตามสแต็ค (หรือบางส่วนของผู้) sys.exec_info()การใช้งาน

รหัสการทำงานขั้นต่ำพร้อมการจัดรูปแบบบางอย่าง:

import sys
import traceback

try:
    ans = 1/0
except BaseException as ex:
    # Get current system exception
    ex_type, ex_value, ex_traceback = sys.exc_info()

    # Extract unformatter stack traces as tuples
    trace_back = traceback.extract_tb(ex_traceback)

    # Format stacktrace
    stack_trace = list()

    for trace in trace_back:
        stack_trace.append("File : %s , Line : %d, Func.Name : %s, Message : %s" % (trace[0], trace[1], trace[2], trace[3]))

    print("Exception type : %s " % ex_type.__name__)
    print("Exception message : %s" %ex_value)
    print("Stack trace : %s" %stack_trace)

ซึ่งให้ผลลัพธ์ต่อไปนี้:

Exception type : ZeroDivisionError
Exception message : division by zero
Stack trace : ['File : .\\test.py , Line : 5, Func.Name : <module>, Message : ans = 1/0']

ฟังก์ชันsys.exc_info ()ให้รายละเอียดเกี่ยวกับข้อยกเว้นล่าสุดให้คุณ มันกลับ tuple (type, value, traceback)ของ

tracebackเป็นตัวอย่างของวัตถุย้อนกลับ คุณสามารถจัดรูปแบบการติดตามด้วยวิธีการที่ให้ไว้ พบได้ในเอกสารประกอบการสืบค้นกลับ


3
การใช้e.__class__.__name__ สามารถส่งคืนคลาสยกเว้นได้เช่นกัน
kenorb

19

คุณสามารถใช้logger.exception("msg")สำหรับการบันทึกข้อยกเว้นด้วยการย้อนกลับ:

try:
    #your code
except Exception as e:
    logger.exception('Failed: ' + str(e))

บังเอิญe.msgเป็นตัวแทนสตริงของExceptionชั้นเรียน
MarkHu

5
logger.exception(e)หรือเพียงแค่
mbdevpl


5

คุณสามารถลองระบุประเภท BaseException ได้อย่างชัดเจน อย่างไรก็ตามสิ่งนี้จะดักจับอนุพันธ์ของ BaseException เท่านั้น แม้ว่าสิ่งนี้จะรวมถึงข้อยกเว้นที่มีการใช้งานทั้งหมด แต่ก็อาจเป็นไปได้ที่จะเพิ่มคลาสแบบเก่าตามอำเภอใจ

try:
  do_something()
except BaseException, e:
  logger.error('Failed to do something: ' + str(e))


2

สำหรับผู้ต่อสู้ในอนาคตใน python 3.8.2 (และอาจมีบางเวอร์ชั่นก่อนหน้านั้น) ไวยากรณ์คือ

except Attribute as e:
    print(e)

1

การใช้str(e)หรือrepr(e)เพื่อเป็นตัวแทนของข้อยกเว้นคุณจะไม่ได้รับการติดตามสแต็กจริงดังนั้นจึงไม่มีประโยชน์ในการค้นหาว่าข้อยกเว้นอยู่ที่ไหน

หลังจากอ่านคำตอบอื่น ๆ และเอกสารแพคเกจการบันทึกสองวิธีต่อไปนี้ใช้งานได้ดีในการพิมพ์การติดตามสแต็คจริงเพื่อการดีบักได้ง่ายขึ้น:

ใช้logger.debug()กับพารามิเตอร์exc_info

try:
    # my code
exception SomeError as e:
    logger.debug(e, exc_info=True)

ใช้ logger.exception()

หรือเราสามารถใช้logger.exception()พิมพ์ข้อยกเว้นได้โดยตรง

try:
    # my code
exception SomeError as e:
    logger.exception(e)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.