Ralat dan pengecualian Python3


Sebagai seorang pemula Python, apabila anda mula-mula mempelajari pengaturcaraan Python, anda akan sering melihat beberapa mesej ralat sebelum ini, tetapi kami akan memperkenalkannya secara khusus dalam bab ini.

Terdapat dua jenis ralat dalam Python yang mudah dikenal pasti: ralat sintaks dan pengecualian.

Ralat sintaks

Ralat sintaks Python, atau ralat penghuraian, sering dihadapi oleh pemula, seperti yang ditunjukkan dalam contoh berikut

>>> while True print('Hello world')
  File "<stdin>", line 1, in ?
    while True print('Hello world')
                   ^
SyntaxError: invalid syntax

Dalam contoh ini, fungsi print() Ralat telah dikesan kerana titik bertindih (:) tiada di hadapannya.

Penghurai menunjukkan baris dalam kesilapan dan menandakan ralat pertama ditemui dengan anak panah kecil.

Pengecualian

Walaupun sintaks program Python betul, ralat mungkin berlaku semasa menjalankannya. Ralat yang dikesan semasa masa jalan dipanggil pengecualian.

Kebanyakan pengecualian tidak akan dikendalikan oleh program dan dipaparkan sebagai mesej ralat di sini:

>>> 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

Pengecualian muncul dalam jenis yang berbeza, dan jenis ini dicetak sebagai sebahagian daripada mesej : Jenis dalam contoh ialah ZeroDivisionError, NameError dan TypeError.

Bahagian hadapan mesej ralat menunjukkan konteks di mana pengecualian berlaku dan memaparkan maklumat khusus dalam bentuk tindanan panggilan.

Pengendalian pengecualian

Dalam contoh berikut, pengguna dibenarkan memasukkan integer sah, tetapi pengguna dibenarkan untuk mengganggu program (menggunakan Control-C atau kaedah yang disediakan oleh operasi sistem). Mesej yang diganggu pengguna menimbulkan pengecualian KeyboardInterrupt.

>>> while True:
        try:
            x = int(input("Please enter a number: "))
            break
        except ValueError:
            print("Oops!  That was no valid number.  Try again   ")

Pernyataan cuba berfungsi seperti berikut;

  • Pertama, klausa cuba (pernyataan antara kata kunci cuba dan kata kunci kecuali) dilaksanakan

  • Jika tiada pengecualian berlaku, abaikan klausa kecuali dan tamatkan selepas klausa cuba dilaksanakan.

  • Jika pengecualian berlaku semasa pelaksanaan klausa cuba, baki klausa cuba akan diabaikan. Jika jenis pengecualian sepadan dengan nama selepas kecuali, klausa kecuali yang sepadan akan dilaksanakan. Akhirnya laksanakan kod selepas pernyataan cuba.

  • Jika pengecualian tidak sepadan dengan mana-mana kecuali, maka pengecualian akan diserahkan kepada percubaan atas.

Pernyataan percubaan mungkin mengandungi berbilang kecuali klausa untuk mengendalikan pengecualian khusus yang berbeza. Paling banyak satu cawangan akan dilaksanakan.

Pengendali hanya akan mengendalikan pengecualian dalam klausa percubaan yang sepadan, bukan pengecualian dalam pengendali percubaan yang lain.

Klausa kecuali boleh mengendalikan berbilang pengecualian pada masa yang sama Pengecualian ini akan diletakkan dalam kurungan untuk membentuk tuple, contohnya:

    except (RuntimeError, TypeError, NameError):
        pass

Klausa kecuali yang terakhir boleh mengabaikan nama bagi. pengecualian , ia akan digunakan sebagai kad bebas. Anda boleh menggunakan kaedah ini untuk mencetak mesej ralat dan kemudian membuang pengecualian sekali lagi.

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

cuba Pernyataan kecuali juga mempunyai klausa lain pilihan Jika klausa ini digunakan, ia mesti diletakkan selepas semua kecuali klausa. Klausa ini akan dilaksanakan jika tiada pengecualian berlaku dalam klausa cuba. Contohnya:

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()

Menggunakan klausa else adalah lebih baik daripada meletakkan semua pernyataan dalam klausa cuba, untuk mengelakkan beberapa pengecualian yang tidak dijangka yang tidak ditangkap oleh kecuali.

Pengendalian pengecualian bukan sahaja mengendalikan pengecualian yang berlaku secara langsung dalam klausa cuba, tetapi juga mengendalikan pengecualian yang dilemparkan dalam fungsi yang dipanggil dalam klausa (malah fungsi dipanggil secara tidak langsung). Contohnya:

>>> 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

Lemparkan pengecualian

Python menggunakan pernyataan raise untuk membuang pengecualian yang ditentukan. Contohnya:

>>> raise NameError('HiThere')
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
NameError: HiThere

raise Satu-satunya parameter menentukan pengecualian untuk dilemparkan. Ia mestilah contoh pengecualian atau kelas pengecualian (iaitu, subkelas Pengecualian).

Jika anda hanya ingin tahu sama ada ini memberikan pengecualian dan tidak mahu mengendalikannya, kenyataan kenaikan yang mudah boleh menimbulkannya semula.

>>> 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

Pengecualian yang ditakrifkan pengguna

Anda boleh mempunyai pengecualian anda sendiri dengan membuat kelas pengecualian baharu. Pengecualian harus diwarisi daripada kelas Pengecualian, sama ada secara langsung atau tidak langsung, contohnya:

>>> 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!'

Dalam contoh ini, lalai __init__() kelas Pengecualian ditindih.

<Kelas pException boleh melakukan apa sahaja seperti kelas lain, tetapi ia biasanya lebih mudah, hanya menyediakan beberapa sifat berkaitan ralat dan membenarkan kod yang mengendalikan pengecualian mendapatkan maklumat ini dengan mudah. < p="">

Apabila mencipta modul yang mungkin membuang banyak pengecualian yang berbeza, pendekatan biasa ialah mencipta kelas pengecualian asas untuk pakej, dan kemudian memberikan ralat yang berbeza berdasarkan kelas asas ini :

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

Kebanyakan nama pengecualian berakhir dengan "Ralat", sama seperti penamaan pengecualian standard.


Tentukan tingkah laku pembersihan

Pernyataan cuba mempunyai klausa pilihan lain yang mentakrifkan tingkah laku pembersihan yang akan dilaksanakan tanpa mengira keadaan. Contohnya:

>>> try:
        raise KeyboardInterrupt
	finally:
        print('Goodbye, world!')
   
Goodbye, world!
KeyboardInterrupt

Dalam contoh di atas, klausa akhirnya akan dilaksanakan tanpa mengira sama ada pengecualian berlaku dalam klausa cuba.

Jika pengecualian dilemparkan dalam klausa cuba (atau dalam klausa kecuali dan lain-lain) dan tiada kecuali untuk menangkapnya, maka pengecualian akan dilemparkan semula selepas klausa akhirnya dilaksanakan.

Berikut ialah contoh yang lebih kompleks (mengandungi kecuali dan akhirnya klausa dalam pernyataan percubaan yang sama):

>>> 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'

Tingkah laku pembersihan yang dipratentukan

Sesetengah Objek mentakrifkan pembersihan standard kelakuan. Tidak kira sama ada sistem berjaya menggunakannya, apabila ia tidak lagi diperlukan, tingkah laku pembersihan standard ini akan dilaksanakan.

Berikut ialah contoh cuba membuka fail dan kemudian mencetak kandungan ke skrin:

for line in open("myfile.txt"):
    print(line, end="")

Masalah dengan kod di atas ialah apabila ia selesai, fail akan kekal terbuka . , dan belum ditutup.

Kata kunci dengan pernyataan boleh memastikan objek seperti fail akan melaksanakan kaedah pembersihannya dengan betul selepas digunakan:

with open("myfile.txt") as f:
    for line in f:
        print(line, end="")

Selepas kod di atas dilaksanakan, walaupun berlaku kesilapan semasa pemprosesan dan fail f sentiasa ditutup.