Python - ยืนยันกับ if & return


12

ฉันกำลังเขียนสคริปต์ที่ทำบางสิ่งบางอย่างกับไฟล์ข้อความ (สิ่งที่ไม่เกี่ยวข้องกับคำถามของฉัน) ดังนั้นก่อนที่ฉันจะทำบางสิ่งกับไฟล์ฉันต้องการตรวจสอบว่ามีไฟล์อยู่หรือไม่ ฉันสามารถทำสิ่งนี้ได้โดยไม่มีปัญหา แต่ปัญหาคือความสวยงาม

นี่คือรหัสของฉันใช้สิ่งเดียวกันในสองวิธีที่แตกต่างกัน

def modify_file(filename):
    assert os.path.isfile(filename), 'file does NOT exist.'


Traceback (most recent call last):
  File "clean_files.py", line 15, in <module>
    print(clean_file('tes3t.txt'))
  File "clean_files.py", line 8, in clean_file
    assert os.path.isfile(filename), 'file does NOT exist.'
AssertionError: file does NOT exist.

หรือ:

def modify_file(filename):
    if not os.path.isfile(filename):
        return 'file does NOT exist.'


file does NOT exist.

วิธีแรกสร้างผลลัพธ์ที่ไม่สำคัญส่วนใหญ่สิ่งเดียวที่ฉันสนใจคือไฟล์ไม่มีอยู่

วิธีที่สองส่งคืนสตริงมันเป็นเรื่องง่าย

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

คำตอบ:


33

คุณต้องการตัวเลือกที่สามแทน: ใช้raiseและข้อยกเว้นเฉพาะ นี่อาจเป็นหนึ่งในข้อยกเว้นในตัวหรือคุณสามารถสร้างข้อยกเว้นแบบกำหนดเองสำหรับงาน

ในกรณีนี้ฉันจะใช้IOErrorแต่ValueErrorอาจพอดี:

def modify_file(filename):
    if not os.path.isfile(filename):
        raise IOError('file does NOT exist.')

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

แน่นอนว่าการดำเนินงานไฟล์จำนวนมาก (เหมือนopen()) ตัวเองเพิ่มOSErrorอยู่แล้ว การทดสอบครั้งแรกอย่างชัดเจนว่าไฟล์ที่มีอยู่อาจซ้ำซ้อนที่นี่

อย่าใช้assert; ถ้าคุณใช้งานไพ ธ อนกับ-Oธงการยืนยันทั้งหมดจะถูกตัดออกจากโค้ด


จุดที่น่าสนใจเกี่ยวกับความซ้ำซ้อน! คุณจะแนะนำให้หลีกเลี่ยงมันได้หรือไม่ นั่นคือ "มันจะล้มเหลวในภายหลัง"
Ciprian Tomoiagă

1
@ CiprianTomoiagă: ทำไมต้องเพิ่มการทดสอบเป็นสองเท่า? ถ้าบรรทัดถัดไปของการmodify_file()เป็นwith open(filename) as f:แล้วIOErrorก็จะได้รับการเลี้ยงดู และเวอร์ชัน Python ล่าสุดได้ให้รายละเอียดเพิ่มเติมในคลาสย่อยของIOError( FileNotFoundErrorโดยเฉพาะอย่างยิ่งนึกถึง) ที่อาจเป็นประโยชน์กับนักพัฒนาโดยใช้ API นี้ หากรหัสทำการตรวจสอบของตนเองและเพิ่มขึ้นIOErrorรายละเอียดที่เป็นประโยชน์จะหายไป
Martijn Pieters

@MartijnPieters จะเป็นคำตอบที่ยอมรับได้ในการ "ทำไมจึงเพิ่มเป็นสองเท่าของการทดสอบ" เมื่อใดที่การตรวจสอบครั้งแรกเร็วกว่าข้อยกเว้นที่เพิ่มขึ้นเมื่อ open () ล้มเหลว เช่นเมื่อตรวจสอบการมีอยู่ของไฟล์จะเร็วกว่าการพยายามเปิดและท้ายที่สุดก็ไม่สามารถทำได้
Marcel Wilson

1
@MarcelWilson: ไม่เพราะคุณต้องปรับให้เหมาะกับวิธีการที่ใช้ I / O ไม่มีจำนวน tweaking ในนาทีความหมายของ Python จะทำให้ I / O ทำงานได้เร็วขึ้นและสร้างความเสียหายต่อความสามารถในการอ่านและการบำรุงรักษาเท่านั้น เน้นไปที่พื้นที่ที่มีผลกระทบมากขึ้นฉันจะบอกว่า
Martijn Pieters

12

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

ค่าของมันค่อนข้าง จำกัด เนื่องจากคุณต้องให้แน่ใจว่าคุณใช้เส้นทางนั้นผ่านรหัสและคุณมักจะต้องการจัดการกับปัญหาเพิ่มเติมด้วยifคำสั่งแยกต่างหากในการผลิต assertมีประโยชน์มากที่สุดในสถานการณ์เช่น "ฉันต้องการแก้ไขปัญหานี้อย่างเป็นประโยชน์หากผู้ใช้พบปัญหา แต่ถ้าผู้พัฒนาประสบปัญหาฉันต้องการให้เกิดความผิดพลาดอย่างหนักเพื่อที่เขาจะแก้ไขรหัสที่เรียกใช้ฟังก์ชันนี้อย่างไม่ถูกต้อง"

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


5

จากUseAssertions อย่างมีประสิทธิภาพ

การตรวจสอบ isinstance () ไม่ควรใช้มากเกินไป: ถ้ามันมีลักษณะเหมือนเป็ดไม่มีความจำเป็นที่จะต้องสอบถามลึกเกินไปว่ามันเป็นจริงหรือไม่ บางครั้งมันอาจมีประโยชน์ในการส่งผ่านค่าที่ไม่ได้คาดไว้โดยโปรแกรมเมอร์ดั้งเดิม

สถานที่ที่จะต้องพิจารณาใส่คำยืนยัน:

checking parameter types, classes, or values
checking data structure invariants
checking "can't happen" situations (duplicates in a list, contradictory state variables.)
after calling a function, to make sure that its return is reasonable 

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

มันง่ายกว่าที่จะรวบรวมข้อมูลที่ไม่ถูกต้อง ณ จุดที่มันเข้าไปมากกว่าจะหาวิธีที่จะไปที่นั่นในภายหลังเมื่อมันทำให้เกิดปัญหา

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

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

หาก Python เริ่มต้นด้วยตัวเลือก -O การยืนยันจะถูกถอดออกและไม่ได้รับการประเมิน ดังนั้นหากรหัสใช้การยืนยันอย่างหนัก แต่มีความสำคัญต่อประสิทธิภาพดังนั้นจึงมีระบบสำหรับการปิดใช้งานในการสร้างรีลีส (แต่อย่าทำเช่นนี้เว้นแต่จำเป็นจริงๆมันได้รับการพิสูจน์ทางวิทยาศาสตร์แล้วว่าข้อบกพร่องบางอย่างจะปรากฏขึ้นเมื่อลูกค้าใช้เครื่องและเราต้องการการยืนยันเพื่อช่วยในที่นั้นด้วย :-))

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