Latest web development tutorials

ข้อผิดพลาดและข้อยกเว้น 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 ปิดให้บริการเสมอ