ปิดใช้งานการยืนยันใน Python


93

ฉันจะปิดใช้งานการยืนยันใน Python ได้อย่างไร

นั่นคือถ้าการยืนยันล้มเหลวฉันไม่ต้องการให้มันโยนAssertionErrorแต่จะทำต่อไป

ฉันจะทำอย่างไร?

คำตอบ:


80

ฉันจะปิดใช้งานการยืนยันใน Python ได้อย่างไร

มีหลายวิธีที่ส่งผลต่อกระบวนการเดียวสภาพแวดล้อมหรือโค้ดบรรทัดเดียว

ฉันสาธิตแต่ละ

สำหรับกระบวนการทั้งหมด

การใช้-Oแฟล็ก (ตัวพิมพ์ใหญ่ O) ปิดใช้งานข้อความยืนยันทั้งหมดในกระบวนการ

ตัวอย่างเช่น:

$ python -Oc "assert False"

$ python -c "assert False"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
AssertionError

โปรดทราบว่าการปิดใช้งานฉันหมายความว่ามันไม่ได้ดำเนินการนิพจน์ที่ตามมา

$ python -Oc "assert 1/0"

$ python -c "assert 1/0"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ZeroDivisionError: integer division or modulo by zero

เพื่อสิ่งแวดล้อม

คุณสามารถใช้ตัวแปรสภาพแวดล้อมเพื่อตั้งค่าสถานะนี้ได้เช่นกัน

สิ่งนี้จะส่งผลต่อทุกกระบวนการที่ใช้หรือสืบทอดสภาพแวดล้อม

เช่นใน Windows ตั้งค่าแล้วล้างตัวแปรสภาพแวดล้อม:

C:\>python -c "assert False"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
AssertionError
C:\>SET PYTHONOPTIMIZE=TRUE

C:\>python -c "assert False"

C:\>SET PYTHONOPTIMIZE=

C:\>python -c "assert False"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
AssertionError

เหมือนกันใน Unix (ใช้ set และunsetสำหรับฟังก์ชันการทำงานที่เกี่ยวข้อง)

จุดเดียวในรหัส

คุณตั้งคำถามต่อไป:

ถ้าการยืนยันล้มเหลวฉันไม่ต้องการให้มันโยน AssertionError แต่จะดำเนินต่อไป

หากคุณต้องการให้ใช้รหัสที่ไม่สามารถใช้งานได้คุณสามารถตรวจจับได้เพื่อให้แน่ใจว่าขั้นตอนการควบคุมไม่ถึงการยืนยันตัวอย่างเช่น

if False:
    assert False, "we know this fails, but we don't get here"

หรือคุณสามารถตรวจจับข้อผิดพลาดในการยืนยัน:

try:
    assert False, "this code runs, fails, and the exception is caught"
except AssertionError as e:
    print(repr(e))

ซึ่งพิมพ์:

AssertionError('this code runs, fails, and the exception is caught')

และคุณจะดำเนินการต่อจากจุดที่คุณจัดการไฟล์AssertionError.

อ้างอิง

จากเอกสาร :assert

ข้อความยืนยันเช่นนี้:

assert expression #, optional_message

เทียบเท่ากับ

if __debug__:
    if not expression: raise AssertionError #(optional_message)

และ,

ตัวแปรในตัว__debug__อยู่Trueภายใต้สถานการณ์ปกติFalseเมื่อมีการร้องขอการเพิ่มประสิทธิภาพ (ตัวเลือกบรรทัดคำสั่ง-O)

และต่อไป

การมอบหมายให้__debug__เป็นสิ่งผิดกฎหมาย ค่าสำหรับตัวแปรบิวท์อินจะถูกกำหนดเมื่อล่ามเริ่มทำงาน

จากเอกสารการใช้งาน:

-O

เปิดการเพิ่มประสิทธิภาพพื้นฐาน สิ่งนี้เปลี่ยนนามสกุลไฟล์สำหรับไฟล์ที่คอมไพล์ (bytecode) จาก. pyc เป็น. pyo โปรดดู PYTHONOPTIMIZE

และ

PYTHONOPTIMIZE

หากตั้งค่าเป็นสตริงที่ไม่ว่างจะเท่ากับการระบุ-Oอ็อพชัน หากตั้งค่าเป็นจำนวนเต็มจะเท่ากับการระบุ-Oหลาย ๆ ครั้ง


เป็นไปได้ไหมที่จะข้ามรหัสที่ล้มเหลวในกรณี 'จุดเดียวในรหัส' ฉันพยายามตั้งค่า__debug__เป็น False แต่ไม่ได้รับอนุญาต
Matthijs

1
@ Matthijs คุณสามารถมั่นใจได้ว่าโฟลว์การควบคุมไปไม่ถึง (เช่นif False: assert False) หรือคุณสามารถตรวจจับข้อผิดพลาดในการยืนยัน นี่คือทางเลือกของคุณ อัปเดตคำตอบเพื่อตอบคำถามของคุณ
Aaron Hall

ขอบคุณสำหรับคำตอบ แต่ยังไม่ครบถ้วนว่าฉันกำลังคิดอะไรอยู่ ฉันต้องการที่จะปิดการใช้งานฟังก์ชั่นอ้างภายในช่วง Runtime นึกคิดกับการจัดเรียงของผู้จัดการบางบริบท: ยืนยันการประเมิน: และยืนยันการปิด:foo() with skip_assertion(): foo()ประโยชน์ของสิ่งนี้ที่ฉันไม่ต้องเพิ่มแฟ
Matthijs

2
คุณสามารถเขียน bytecode ของฟังก์ชันใหม่เขียน AST ใหม่หรือเขียนฟังก์ชันใหม่ได้ (ด้วยตนเองหรือทางโปรแกรมสำหรับอย่างใดอย่างหนึ่ง) การเขียน AST ใหม่น่าจะเป็นแนวทางที่น่าเชื่อถือที่สุด ("เพียง" แทนที่Assertวัตถุด้วยPassวัตถุ) ตัวจัดการบริบทจะไม่ทำงานโดยตรงสำหรับสิ่งนั้น แต่คุณสามารถมีกลไกบางอย่างที่ใช้ฟังก์ชันตกแต่งในลักษณะนั้น ไม่ว่าฉันจะไม่แนะนำ ฉันสงสัยว่าเหตุผลของคุณที่ต้องการทำเช่นนั้นคือคุณกำลังเรียกรหัสที่คุณไม่ได้ควบคุมและได้รับ AssertionErrors หากเป็นเช่นนั้นคุณอาจต้องหาวิธีแก้ไขอื่น
Aaron Hall

60

เรียก Python ด้วยแฟล็ก -O:

test.py:

assert(False)
print 'Done'

เอาท์พุต:

C:\temp\py>C:\Python26\python.exe test.py
Traceback (most recent call last):
  File "test.py", line 1, in <module>
    assert(False)
AssertionError

C:\temp\py>C:\Python26\python.exe -O test.py
Done

9
Assert ไม่ใช่ฟังก์ชันดังนั้น parens จึงไม่จำเป็น
Aaron Hall

15

คำตอบทั้งสองคำตอบนั้นถูกต้อง (เรียก Python ด้วยบรรทัดคำสั่งอย่างใดอย่างหนึ่ง-Oหรือ-OOในบรรทัดคำสั่ง)

นี่คือความแตกต่างระหว่างพวกเขา:

  • -Oเปิดการเพิ่มประสิทธิภาพพื้นฐาน สิ่งนี้เปลี่ยนนามสกุลไฟล์สำหรับไฟล์ที่คอมไพล์ (bytecode) จาก. pyc เป็น. pyo

  • -OOทิ้ง docstrings นอกเหนือจากการปรับให้-Oเหมาะสม

(จากเอกสาร Python )



3

คุณไม่ควรปิดใช้งานการยืนยัน (ส่วนใหญ่) พวกเขาจับข้อผิดพลาดที่ไม่คาดคิดเมื่อความสนใจอยู่ที่อื่น ดูกฎข้อที่ 5 ใน"พลังสิบ"

ให้ป้องกันการตรวจสอบการยืนยันที่มีราคาแพงบางอย่างเช่น:

import logging
logger = logging.getLogger(__name__)

if logger.getEffectiveLevel() < logging.DEBUG:
    ok = check_expensive_property()
    assert ok, 'Run !'

วิธีหนึ่งในการรักษาคำยืนยันที่สำคัญและอนุญาตให้assertข้อความถูกปรับให้เหมาะสมที่สุดคือการเพิ่มขึ้นภายในคำสั่งการเลือก:

if foo_is_broken():
    raise AssertionError('Foo is broken!')

1
// แต่ปัญหาคือคำสั่งยังคงเพิ่มความซับซ้อนของวัฏจักรและการจัดการข้อผิดพลาดควรจัดการส่วนที่เหลือหรือไม่?
Nathan Basanese

1
คำยืนยันที่จะได้รับการปกป้องดังกล่าวข้างต้นคือการโทรที่มีราคาแพงซึ่งทำให้การดำเนินการช้าลงอย่างมาก สำหรับอัลกอริทึมบางอย่างการตรวจสอบประเภทนี้อาจใช้ลำดับความสำคัญนานกว่าโปรแกรมทั้งหมด ลองนึกถึงการใช้งานที่ไร้เดียงสา แต่ง่ายกว่า (มีโอกาสน้อยที่จะมีข้อผิดพลาด) ของอัลกอริทึมเดียวกันเพื่อตรวจสอบความถูกต้อง หรือตรวจสอบโดยการแจกแจงอย่างละเอียดถี่ถ้วนของสิ่งที่ไม่ตรงประเด็นสำหรับการทำงานปกติ
Ioannis Filippidis

ฉันไม่เห็นปัญหาเกี่ยวกับความสามารถในการอ่านมากนักเนื่องจากคำสั่งดังกล่าวไม่ได้เพิ่มการซ้อนลงในโค้ด การแยกมันเป็นการเรียกใช้ฟังก์ชันสามารถย้ายออกไปได้หากเป็นปัญหา (และฉันคาดว่าการปรับโครงสร้างดังกล่าวควรลดความซับซ้อนของวัฏจักร) ไม่ว่าในกรณีใดความซับซ้อนของวัฏจักรไม่ควรควบคุมการตรวจสอบความปลอดภัย
Ioannis Filippidis

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