ใน Python เราจะจับคำเตือนได้อย่างไรว่าเป็นข้อยกเว้น


105

ไลบรารีของบุคคลที่สาม (เขียนด้วย C) ที่ฉันใช้ในโค้ด python ของฉันกำลังออกคำเตือน ฉันต้องการใช้try exceptไวยากรณ์เพื่อจัดการกับคำเตือนเหล่านี้อย่างถูกต้อง มีวิธีทำไหม?


2
คำเตือนเหล่านั้นเป็นเพียงข้อความที่เขียนขึ้นเพื่อ stderr หรือไม่?
Fenikso

1
Fenikso: ฉันไม่รู้แน่ชัดดูเหมือนคำเตือนที่แท้จริง
Boris Gorelik

1
คุณรู้จัก "คำเตือนที่แท้จริง" ได้อย่างไร? ฉันคิดว่าใน C คุณจะได้รับคำเตือนที่แท้จริงระหว่างการคอมไพล์
Fenikso

warnings.filterwarningsไม่ตรงตามที่คุณต้องการฉันไม่เข้าใจว่าปัญหาของคุณคืออะไร?
Rosh Oxymoron

4
@Fenikso, @Rosh Oxymoron คุณพูดถูก ความผิดพลาดของฉัน. warnings.filterwarnigns('error')ทำงาน ฉันไม่พบคำตอบเดิมที่เสนอวิธีแก้ปัญหานี้
Boris Gorelik

คำตอบ:


52

อ้างจากคู่มือ python ( 27.6.4 คำเตือนการทดสอบ ):

import warnings

def fxn():
    warnings.warn("deprecated", DeprecationWarning)

with warnings.catch_warnings(record=True) as w:
    # Cause all warnings to always be triggered.
    warnings.simplefilter("always")
    # Trigger a warning.
    fxn()
    # Verify some things
    assert len(w) == 1
    assert issubclass(w[-1].category, DeprecationWarning)
    assert "deprecated" in str(w[-1].message)

6
นี่คือคำตอบซึ่งจะบอกวิธีใช้try exceptไวยากรณ์
Unapiedra

สิ่งนี้มีข้อดีกว่าคำตอบของ niekas คือหากfnxส่งคืนบางสิ่งคุณจะเก็บผลลัพธ์นั้นไว้ (และยังสามารถจัดการคำเตือนได้)
Pietro Battiston

สิ่งนี้ไม่ตอบคำถามของ OP ซึ่งเกี่ยวกับการจัดการ wanrings ไม่ใช่การทดสอบ อย่างไรก็ตามคำตอบของ niekas ด้านล่างแสดงวิธีจัดการคำเตือน
Biggsy

โปรดทราบว่าฟังก์ชันข้างต้นจะไม่ทำงานหากฟังก์ชันของคุณส่งคืนคำเตือนเป็นระยะ ๆ เท่านั้นเนื่องจากในกรณีที่fxn()ไม่ส่งคืนคำเตือนwจะเป็นรายการว่างเปล่า หากwเป็นรายการที่ว่างเปล่า (เช่น[]) IndexError: list index out of rangeจากนั้นใช้รหัสที่จะทำให้คุณข้อผิดพลาดต่อไปนี้: หากคุณต้องการจัดรูปแบบหรือตรวจสอบคุณสมบัติของคำเตือนที่บันทึกไว้คุณควรใช้ for-loop:for x in w: print(f'{x.category.__name__}: {str(x.message)}')
Steven M. Mortimer

132

ในการจัดการคำเตือนที่เป็นข้อผิดพลาดให้ใช้สิ่งนี้:

import warnings
warnings.filterwarnings("error")

หลังจากนี้คุณจะสามารถรับคำเตือนเช่นเดียวกับข้อผิดพลาดเช่นจะใช้งานได้:

try:
    some_heavy_calculations()
except RuntimeWarning:
    import ipdb; ipdb.set_trace()

PS เพิ่มคำตอบนี้เพราะคำตอบที่ดีที่สุดในการแสดงความคิดเห็นที่มีการสะกดคำผิด: แทนfilterwarnignsfilterwarnings


8
และถ้าคุณแค่ต้องการดูสแต็กแทร็กสองบรรทัดแรกคือทั้งหมดที่คุณต้องการ
z0r

5
เหมาะมากครับ ฉันแค่ต้องการให้สคริปต์ของฉันหยุดดำเนินการทันทีที่มีการออกคำเตือนเพื่อที่ฉันจะได้พิมพ์ข้อมูลการดีบักที่เกี่ยวข้องและแก้ไขปัญหาได้
ประวีณ

1
คุณไม่จำเป็นต้องใช้filterwarningsสายเพื่อที่จะจับWarningsได้อย่างน้อยใน python 3 ก็ใช้งานได้
naught101

1
คำตอบที่ยอมรับไม่ตอบคำถามของ OP คำตอบนี้ไม่ นี่คือคำตอบที่ฉันกำลังมองหาเมื่อการค้นหาพบคำถามนี้
Biggsy

16

นี่คือรูปแบบที่ทำให้ชัดเจนขึ้นว่าจะทำงานกับคำเตือนที่กำหนดเองของคุณอย่างไร

import warnings
with warnings.catch_warnings(record=True) as w:
    # Cause all warnings to always be triggered.
    warnings.simplefilter("always")

    # Call some code that triggers a custom warning.
    functionThatRaisesWarning()

    # ignore any non-custom warnings that may be in the list
    w = filter(lambda i: issubclass(i.category, UserWarning), w)

    if len(w):
        # do something with the first warning
        email_admins(w[0].message)


4

ในบางกรณีคุณต้องใช้ ctypes เพื่อเปลี่ยนคำเตือนให้เป็นข้อผิดพลาด ตัวอย่างเช่น:

str(b'test')  # no error
import warnings
warnings.simplefilter('error', BytesWarning)
str(b'test')  # still no error
import ctypes
ctypes.c_int.in_dll(ctypes.pythonapi, 'Py_BytesWarningFlag').value = 2
str(b'test')  # this raises an error

คำตอบนี้สร้างสรรค์เพียงเพื่อแสดงข้อผิดพลาดในคำเตือนบางประเภทเท่านั้น สำหรับโครงการซอฟต์แวร์ขนาดใหญ่เกือบทุกโครงการหากคุณwarnings.simplefilter('error')ไม่ได้รับการตรวจสอบย้อนกลับสำหรับคำเตือนที่คุณเห็นในบันทึก แต่จะได้รับการตรวจสอบย้อนกลับจากคำเตือนที่กรองไว้ก่อนหน้านี้แทน การใช้simplefilterยังเป็นวิธีที่เร็วที่สุดในการได้รับคำตอบหากคุณมีการร้องขอ CLI
AlanSE
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.