ข้อผิดพลาดและข้อยกเว้น Python3
เป็นผู้เริ่มต้นหลามเพียงการเรียนรู้การเขียนโปรแกรมหลามมักจะเห็นข้อผิดพลาดบางอย่างที่เราไม่ได้พูดถึงในหน้าของบทนี้เราจะทุ่มเท
งูหลามมีสองข้อผิดพลาดที่จดจำได้ง่าย: ข้อผิดพลาดทางไวยากรณ์และข้อยกเว้น
ไวยากรณ์ผิดพลาด
งูหลามข้อผิดพลาดทางไวยากรณ์หรือการวิเคราะห์โทรผิดเริ่มต้นมักจะพบเป็นตัวอย่าง
>>> while True print('Hello world') File "<stdin>", line 1, in ? while True print('Hello world') ^ SyntaxError: invalid syntax
ในตัวอย่างนี้พิมพ์ฟังก์ชั่น () มีการตรวจสอบข้อผิดพลาดก่อนที่มันจะหายไปโคลอน (:)
แยกวิเคราะห์ชี้ให้เห็นข้อผิดพลาดของพรรคของเขาและในสถานที่ที่ไม่ถูกต้องที่จะหาเครื่องหมายแรกลูกศรขนาดเล็ก
ผิดปกติ
แม้โปรแกรมไวยากรณ์หลามถูกต้องมันเป็นเวลาในการทำงานอาจจะมีข้อผิดพลาด Runtime ข้อผิดพลาดที่ตรวจพบจะถูกเรียกว่าข้อยกเว้น
ส่วนใหญ่จะไม่จัดการข้อยกเว้นในรูปแบบของการแสดงผลข้อความผิดพลาดที่นี่:
>>> 10 * (1/0) Traceback (most recent call last): File "<stdin>", line 1, in ? ZeroDivisionError: division by zero >>> 4 + spam*3 Traceback (most recent call last): File "<stdin>", line 1, in ? NameError: name 'spam' is not defined >>> '2' + 2 Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: Can't convert 'int' object to str implicitly
ปรากฏความผิดปกติในรูปแบบที่แตกต่างกันประเภทเหล่านี้จะถูกพิมพ์ออกมาเป็นส่วนหนึ่งของข้อมูล: ตัวอย่างของประเภท ZeroDivisionError, NameError และ TypeError
ส่วนด้านหน้าของข้อผิดพลาดที่แสดงให้เห็นบริบทของข้อยกเว้นเกิดขึ้นเรียกกองและแสดงผลในรูปแบบของข้อมูลเฉพาะที่
การจัดการข้อยกเว้น
ตัวอย่างต่อไปนี้ช่วยให้ผู้ใช้ป้อนจำนวนเต็มถูกต้อง แต่ช่วยให้ผู้ใช้เพื่อขัดขวางโปรแกรม (โดยใช้การควบคุม-C หรือวิธีการระบบปฏิบัติการที่ให้ไว้) การหยุดชะงักของผู้ใช้จะทำให้เกิดข้อยกเว้น KeyboardInterrupt
>>> while True: try: x = int(input("Please enter a number: ")) break except ValueError: print("Oops! That was no valid number. Try again ")
ลองงานคำสั่งดังต่อไปนี้
- ก่อนที่ข้อลอง (ระหว่างคำหลักและคำหลักยกเว้นงบ TRY)
- หากไม่มีข้อยกเว้นเกิดขึ้นข้อยกเว้นจะถูกละเว้นข้อลองจะถูกดำเนินการปลาย
- หากข้อยกเว้นเกิดขึ้นในขั้นตอนข้อลองแล้วลองข้อส่วนที่เหลือจะถูกละเว้น หากชื่อและประเภทของข้อยกเว้นยกเว้นหลังจากที่การแข่งขันแล้วสอดคล้องข้อยกเว้นจะถูกดำเนินการ รหัสลองคำสั่งหลังจากการดำเนินการที่ผ่านมา
- หากมีข้อยกเว้นไม่ตรงกับใด ๆ ยกเว้นข้อยกเว้นนี้จะถูกส่งผ่านไปยังลองบน
คำสั่งลองอาจมีมากกว่าหนึ่งข้อยกเว้นการจัดการกับข้อยกเว้นเฉพาะที่แตกต่างกัน สาขามากที่สุดคนหนึ่งจะถูกดำเนินการ
จัดการเฉพาะสำหรับการประมวลผลที่สอดคล้องกันลองข้อยกเว้นมากกว่าตัวจัดการลองยกเว้นอื่น ๆ
เว้นแต่เป็นข้อสามารถจัดการกับข้อยกเว้นหลายตัวที่จะถูกวางไว้ในวงเล็บเป็น tuple ตัวอย่างเช่น:
except (RuntimeError, TypeError, NameError): pass
สุดท้ายข้อยกเว้นอาจจะไม่สนใจชื่อของข้อยกเว้นก็จะได้รับการปฏิบัติเป็นสัญลักษณ์แทน คุณสามารถใช้วิธีนี้เพื่อพิมพ์ข้อความผิดพลาดแล้วโยนอีกครั้ง
import sys try: f = open('myfile.txt') s = f.readline() i = int(s.strip()) except OSError as err: print("OS error: {0}".format(err)) except ValueError: print("Could not convert data to an integer.") except: print("Unexpected error:", sys.exc_info()[0]) raise
ลองยกเว้นคำสั่งมีข้ออื่นไม่จำเป็นถ้าคุณใช้ข้อนี้จะต้องวางอยู่หลังทั้งหมดยกเว้นคำสั่ง ข้อนี้จะไม่ได้มีปัญหาใด ๆ เกิดขึ้นในข้อรันลอง ตัวอย่างเช่น:
for arg in sys.argv[1:]: try: f = open(arg, 'r') except IOError: print('cannot open', arg) else: print(arg, 'has', len(f.readlines()), 'lines') f.close()
ใช้ข้ออื่นกว่างบทั้งหมดที่อยู่ในข้อลองซึ่งดีกว่าที่จะหลีกเลี่ยงการที่ไม่คาดคิดบางอย่าง แต่ยกเว้นพวกเขาไม่ได้จับข้อยกเว้น
การจัดการข้อยกเว้นไม่เพียง แต่จัดการกับข้อยกเว้นเหล่านั้นเกิดขึ้นโดยตรงลองข้อ แต่ยังจะเรียกข้อจัดการ (แม้ทางอ้อมเรียกฟังก์ชัน) ที่โยน ตัวอย่างเช่น:
>>> def this_fails(): x = 1/0 >>> try: this_fails() except ZeroDivisionError as err: print('Handling run-time error:', err) Handling run-time error: int division or modulo by zero
โยนข้อยกเว้น
งูหลามคำสั่งจากเส้นข้างใช้ในการเพิ่มข้อยกเว้นที่ระบุไว้ ตัวอย่างเช่น:
>>> raise NameError('HiThere') Traceback (most recent call last): File "<stdin>", line 1, in ? NameError: HiThere
เพิ่มเพียงหนึ่งพารามิเตอร์ระบุข้อยกเว้นจะถูกโยน มันจะต้องเป็นตัวอย่างที่ผิดปกติของชั้นเรียนหรือผิดปกติ (เช่น subclass ข้อยกเว้น)
ถ้าคุณต้องการที่จะรู้ว่าถ้ามันจะพ่นยกเว้นไม่ต้องการที่จะจัดการกับมันแล้วคำสั่งง่ายๆสามารถยกมันโยนอีกครั้ง
>>> try: raise NameError('HiThere') except NameError: print('An exception flew by!') raise An exception flew by! Traceback (most recent call last): File "<stdin>", line 2, in ? NameError: HiThere
ข้อยกเว้นที่ผู้ใช้กำหนด
คุณสามารถมีข้อยกเว้นของคุณเองโดยการสร้างชั้นยกเว้นใหม่ ข้อยกเว้นควรสืบทอดจากคลาสข้อยกเว้นไม่ว่าโดยตรงรับมรดกสืบทอดหรือทางอ้อมเช่น:
>>> class MyError(Exception): def __init__(self, value): self.value = value def __str__(self): return repr(self.value) >>> try: raise MyError(2*2) except MyError as e: print('My exception occurred, value:', e.value) My exception occurred, value: 4 >>> raise MyError('oops!') Traceback (most recent call last): File "<stdin>", line 1, in ? __main__.MyError: 'oops!'
ในตัวอย่างนี้ชั้นยกเว้นค่าเริ่มต้น __ __init () ถูกเขียนทับ
เมื่อมีการสร้างโมดูลอาจจะโยนความหลากหลายของความผิดปกติของการปฏิบัติร่วมกันคือการสร้างชั้นฐานข้อยกเว้นสำหรับแพคเกจนี้และจากนั้นขึ้นอยู่กับชั้นฐานนี้เพื่อสร้างย่อยเรียนแตกต่างกันสำหรับเงื่อนไขข้อผิดพลาดที่แตกต่างกัน
class Error(Exception): """Base class for exceptions in this module.""" pass class InputError(Error): """Exception raised for errors in the input. Attributes: expression -- input expression in which the error occurred message -- explanation of the error """ def __init__(self, expression, message): self.expression = expression self.message = message class TransitionError(Error): """Raised when an operation attempts a state transition that's not allowed. Attributes: previous -- state at beginning of transition next -- attempted new state message -- explanation of why the specific transition is not allowed """ def __init__(self, previous, next, message): self.previous = previous self.next = next self.message = message
ส่วนใหญ่ของชื่อเป็นข้อยกเว้นที่จะ "ข้อผิดพลาด" ในตอนท้ายเช่นเดียวกับการตั้งชื่อมาตรฐานที่ผิดปกติ
กำหนดพฤติกรรมการทำความสะอาด
ลองคำสั่งมีอีกข้อที่ไม่จำเป็นซึ่งกำหนดพฤติกรรมสะอาดขึ้นภายใต้สถานการณ์ใด ๆ ที่จะดำเนินการ ตัวอย่างเช่น:
>>> try: raise KeyboardInterrupt finally: print('Goodbye, world!') Goodbye, world! KeyboardInterrupt
โดยไม่คำนึงถึงตัวอย่างข้างต้นลองข้อไม่มีข้อยกเว้นเกิดขึ้นในที่สุดข้อจะถูกดำเนินการ
หากมีข้อยกเว้นในข้อลอง (หรือยกเว้นและข้ออื่น) ถูกโยนออกมา แต่ไม่ได้ใด ๆ ยกเว้นว่ามันจะหยุดแล้วนี้จะเพิ่มขึ้นอีกครั้งหลังจากที่ในที่สุดก็จะถูกดำเนินการข้อ
นี่เป็นตัวอย่างที่ซับซ้อนมากขึ้น (ที่มีอยู่ในคำสั่งเดียวกันในลองยกเว้นและข้อสุดท้าย):
>>> def divide(x, y): try: result = x / y except ZeroDivisionError: print("division by zero!") else: print("result is", result) finally: print("executing finally clause") >>> divide(2, 1) result is 2.0 executing finally clause >>> divide(2, 0) division by zero! executing finally clause >>> divide("2", "1") executing finally clause Traceback (most recent call last): File "<stdin>", line 1, in ? File "<stdin>", line 3, in divide TypeError: unsupported operand type(s) for /: 'str' and 'str'
พฤติกรรมการทำความสะอาดที่กำหนดไว้ล่วงหน้า
วัตถุบางอย่างกำหนดมาตรฐานพฤติกรรมสะอาดขึ้นโดยไม่คำนึงถึงว่าระบบใช้ประสบความสำเร็จเพียงครั้งเดียวไม่จำเป็นต้องใช้แล้วทำความสะอาดพฤติกรรมมาตรฐานนี้จะถูกดำเนินการ
ตัวอย่างนี้แสดงข้างนี้พยายามเปิดแฟ้มแล้วพิมพ์เนื้อหาบนหน้าจอ:
for line in open("myfile.txt"): print(line, end="")
ปัญหาดังกล่าวด้วยรหัสนี้ก็คือว่าเมื่อเสร็จแล้วไฟล์ที่ยังคงเปิดไม่ได้ปิด
คำหลักที่มีคำสั่งสามารถรับประกันวัตถุดังกล่าวเป็นไฟล์จะเสร็จสิ้นการใช้การดำเนินการที่ถูกต้องของวิธีการทำความสะอาดของเขา
with open("myfile.txt") as f: for line in f: print(line, end="")
หลังจากโค้ดข้างต้นเสร็จสิ้นแม้ว่าปัญหาในกระบวนการแฟ้ม F ปิดให้บริการเสมอ