Cara Mengendalikan Pengecualian di Python: Pengenalan Visual Terperinci

Selamat Datang! Dalam artikel ini, anda akan belajar bagaimana menangani pengecualian di Python.

Khususnya, kami akan merangkumi:

  • Pengecualian
  • Tujuan pengendalian pengecualian
  • Fasal cubaan
  • Klausa kecuali
  • Fasal yang lain
  • Klausa akhirnya
  • Cara meningkatkan pengecualian

Adakah anda sudah bersedia? Mari kita mulakan! ?

1️⃣ Pengenalan kepada Pengecualian

Kami akan memulakan dengan pengecualian:

  • Apa itu?
  • Mengapa ia relevan?
  • Mengapa anda mesti mengatasinya?

Menurut dokumentasi Python:

Kesalahan yang dikesan semasa pelaksanaan disebut pengecualian dan tidak membawa maut tanpa syarat.

Pengecualian ditimbulkan apabila program mengalami kesalahan semasa pelaksanaannya. Mereka mengganggu aliran normal program dan biasanya mengakhirinya secara tiba-tiba. Untuk mengelakkan ini, anda dapat menangkapnya dan mengatasinya dengan betul.

Anda mungkin pernah melihatnya semasa projek pengaturcaraan anda.

Sekiranya anda pernah cuba membahagi dengan sifar di Python, anda pasti melihat mesej ralat ini:

>>> a = 5/0 Traceback (most recent call last): File "", line 1, in  a = 5/0 ZeroDivisionError: division by zero

Sekiranya anda cuba mengindeks rentetan dengan indeks yang tidak betul, anda pasti mendapat mesej ralat ini:

>>> a = "Hello, World" >>> a[456] Traceback (most recent call last): File "", line 1, in  a[456] IndexError: string index out of range

Ini adalah contoh pengecualian.

? Pengecualian Umum

Terdapat banyak jenis pengecualian, dan semuanya dikemukakan dalam situasi tertentu. Beberapa pengecualian yang kemungkinan besar akan anda lihat semasa anda mengerjakan projek anda adalah:

  • IndexError - dinaikkan ketika anda cuba mengindeks senarai, tuple, atau rentetan di luar batas yang dibenarkan. Sebagai contoh:
>>> num = [1, 2, 6, 5] >>> num[56546546] Traceback (most recent call last): File "", line 1, in  num[56546546] IndexError: list index out of range
  • KeyError - dinaikkan semasa anda cuba mengakses nilai kunci yang tidak ada dalam kamus. Sebagai contoh:
>>> students = {"Nora": 15, "Gino": 30} >>> students["Lisa"] Traceback (most recent call last): File "", line 1, in  students["Lisa"] KeyError: 'Lisa'
  • NameError - dibangkitkan apabila nama yang anda rujuk dalam kod tidak ada. Sebagai contoh:
>>> a = b Traceback (most recent call last): File "", line 1, in  a = b NameError: name 'b' is not defined
  • TypeError - dibangkitkan apabila operasi atau fungsi diterapkan pada objek jenis yang tidak sesuai. Sebagai contoh:
>>> (5, 6, 7) * (1, 2, 3) Traceback (most recent call last): File "", line 1, in  (5, 6, 7) * (1, 2, 3) TypeError: can't multiply sequence by non-int of type 'tuple'
  • ZeroDivisionError - dinaikkan semasa anda cuba membahagi dengan sifar.
>>> a = 5/0 Traceback (most recent call last): File "", line 1, in  a = 5/0 ZeroDivisionError: division by zero

? Petua: Untuk mengetahui lebih lanjut mengenai jenis pengecualian bawaan lain, sila rujuk artikel ini dalam Dokumentasi Python.

? Anatomi Pengecualian

Saya pasti bahawa anda pasti melihat corak umum dalam mesej ralat ini. Mari pecahkan struktur umum mereka secara berasingan:

Pertama, kita dapati garis ini (lihat di bawah). A traceback pada dasarnya ialah senarai memperincikan fungsi panggilan yang telah dibuat sebelum pengecualian dinaikkan.

Jejak balik membantu anda semasa proses penyahpepijatan kerana anda dapat menganalisis urutan panggilan fungsi yang mengakibatkan pengecualian:

Traceback (most recent call last):

Kemudian, kita melihat baris ini (lihat di bawah) dengan jalan ke fail dan garis yang menimbulkan pengecualian. Dalam kes ini, jalannya adalah shell Python kerana contohnya dilaksanakan secara langsung di IDLE.

File "", line 1, in  a - 5/0

? Petua: Jika garis yang menaikkan pengecualian termasuk dalam fungsi, diganti dengan nama fungsi.

Akhirnya, kami melihat mesej deskriptif yang memperincikan jenis pengecualian dan memberikan maklumat tambahan untuk membantu kami menyahpepijat kod:

NameError: name 'a' is not defined

2️⃣ Pengendalian Pengecualian: Tujuan & Konteks

Anda mungkin bertanya: mengapa saya mahu menangani pengecualian? Mengapa ini berguna untuk saya? Dengan menangani pengecualian, anda dapat memberikan aliran pelaksanaan alternatif untuk mengelakkan program anda tidak disangka secara tiba-tiba.

? Contoh: Input Pengguna

Bayangkan apa yang akan berlaku sekiranya pengguna yang bekerja dengan program anda memasukkan input yang tidak sah. Ini akan menimbulkan pengecualian kerana operasi yang tidak sah dilakukan semasa proses tersebut.

Sekiranya program anda tidak mengendalikannya dengan betul, program itu akan tiba-tiba hancur dan pengguna akan mendapat pengalaman yang sangat mengecewakan dengan produk anda.

Tetapi jika anda menangani pengecualian, anda akan dapat memberikan alternatif untuk meningkatkan pengalaman pengguna.

Perhaps you could display a descriptive message asking the user to enter a valid input, or you could provide a default value for the input. Depending on the context, you can choose what to do when this happens, and this is the magic of error handling. It can save the day when unexpected things happen. ⭐️

? What Happens Behind the Scenes?

Basically, when we handle an exception, we are telling the program what to do if the exception is raised. In that case, the "alternative" flow of execution will come to the rescue. If no exceptions are raised, the code will run as expected.

3️⃣ Time to Code: The try ... except Statement

Now that you know what exceptions are and why you should we handle them, we will start diving into the built-in tools that the Python languages offers for this purpose.

First, we have the most basic statement: try ... except.

Let's illustrate this with a simple example. We have this small program that asks the user to enter the name of a student to display his/her age:

students = {"Nora": 15, "Gino": 30} def print_student_age(): name = input("Please enter the name of the student: ") print(students[name]) print_student_age()

Notice how we are not validating user input at the moment, so the user might enter invalid values (names that are not in the dictionary) and the consequences would be catastrophic because the program would crash if a KeyError is raised:

# User Input Please enter the name of the student: "Daniel" # Error Message Traceback (most recent call last): File "", line 15, in  print_student_age() File "", line 13, in print_student_age print(students[name]) KeyError: '"Daniel"'

? Syntax

We can handle this nicely using try ... except. This is the basic syntax:

In our example, we would add the try ... except statement within the function. Let's break this down piece by piece:

students = {"Nora": 15, "Gino": 30} def print_student_age(): while True: try: name = input("Please enter the name of the student: ") print(students[name]) break except: print("This name is not registered") print_student_age()

If we "zoom in", we see the try ... except statement:

try: name = input("Please enter the name of the student: ") print(students[name]) break except: print("This name is not registered")
  • When the function is called, the try clause will run. If no exceptions are raised, the program will run as expected.
  • But if an exception is raised in the try clause, the flow of execution will immediately jump to the except clause to handle the exception.

? Note: This code is contained within a while loop to continue asking for user input if the value is invalid. This is an example:

Please enter the name of the student: "Lulu" This name is not registered Please enter the name of the student: 

This is great, right? Now we can continue asking for user input if the value is invalid.

At the moment, we are handling all possible exceptions with the same except clause. But what if we only want to handle a specific type of exception? Let's see how we could do this.

? Catching Specific Exceptions

Since not all types of exceptions are handled in the same way, we can specify which exceptions we would like to handle with this syntax:

This is an example. We are handling the ZeroDivisionError exception in case the user enters zero as the denominator:

def divide_integers(): while True: try: a = int(input("Please enter the numerator: ")) b = int(input("Please enter the denominator: ")) print(a / b) except ZeroDivisionError: print("Please enter a valid denominator.") divide_integers()

Ini akan menjadi hasilnya:

# First iteration Please enter the numerator: 5 Please enter the denominator: 0 Please enter a valid denominator. # Second iteration Please enter the numerator: 5 Please enter the denominator: 2 2.5

Kami menangani ini dengan betul. Tetapi ... jika ada jenis pengecualian lain, program ini tidak akan dapat dikendalikan dengan baik.

Di sini kita mempunyai contoh ValueError kerana salah satu nilainya adalah float, bukan int:

Please enter the numerator: 5 Please enter the denominator: 0.5 Traceback (most recent call last): File "", line 53, in  divide_integers() File "", line 47, in divide_integers b = int(input("Please enter the denominator: ")) ValueError: invalid literal for int() with base 10: '0.5'

Kami dapat menyesuaikan cara kami menangani pelbagai jenis pengecualian.

? Pelbagai Klausa Kecuali

Untuk melakukan ini, kita perlu menambahkan beberapa exceptklausa untuk menangani pelbagai jenis pengecualian secara berbeza.

Menurut Dokumentasi Python:

Pernyataan cuba mungkin mempunyai lebih dari satu kecuali klausa , untuk menentukan pengendali untuk pengecualian yang berbeza. Paling banyak satu pengendali akan dilaksanakan .

Dalam contoh ini, kita mempunyai dua kecuali klausa. Salah satunya mengendalikan ZeroDivisionError dan yang lain menangani ValueError, dua jenis pengecualian yang boleh dikemukakan dalam blok percubaan ini.

def divide_integers(): while True: try: a = int(input("Please enter the numerator: ")) b = int(input("Please enter the denominator: ")) print(a / b) except ZeroDivisionError: print("Please enter a valid denominator.") except ValueError: print("Both values have to be integers.") divide_integers() 

? Petua: Anda harus menentukan jenis pengecualian mana yang mungkin ditimbulkan di blok percubaan untuk menanganinya dengan tepat.

? Pelbagai Pengecualian, Satu kecuali Klausa

Anda juga boleh memilih untuk menangani pelbagai jenis pengecualian dengan yang sama kecuali klausa.

Menurut Dokumentasi Python:

Klausa kecuali boleh menamakan beberapa pengecualian sebagai tuple yang diberi tanda kurung.

Ini adalah contoh di mana kita memperoleh dua pengecualian (ZeroDivisionError dan ValueError) dengan exceptklausa yang sama :

def divide_integers(): while True: try: a = int(input("Please enter the numerator: ")) b = int(input("Please enter the denominator: ")) print(a / b) except (ZeroDivisionError, ValueError): print("Please enter valid integers.") divide_integers()

Hasilnya akan sama untuk dua jenis pengecualian kerana ia dikendalikan oleh yang sama kecuali klausa:

Please enter the numerator: 5 Please enter the denominator: 0 Please enter valid integers.
Please enter the numerator: 0.5 Please enter valid integers. Please enter the numerator: 

? Mengendalikan Pengecualian yang Ditimbulkan oleh Fungsi yang disebut dalam Klausa percubaan

Aspek menarik dari pengendalian pengecualian adalah bahawa jika pengecualian dibangkitkan dalam fungsi yang sebelumnya disebut dalam klausa percubaan fungsi lain dan fungsi itu sendiri tidak menanganinya, pemanggil akan menanganinya jika ada klausa kecuali yang sesuai.

Menurut Dokumentasi Python:

Pengendali pengecualian tidak hanya menangani pengecualian jika berlaku dalam klausa percubaan, tetapi juga jika mereka berlaku di dalam fungsi yang disebut (bahkan tidak langsung) dalam klausa percubaan.

Mari lihat contoh untuk menggambarkan ini:

def f(i): try: g(i) except IndexError: print("Please enter a valid index") def g(i): a = "Hello" return a[i] f(50)

We have the f function and the g function. f calls g in the try clause. With the argument 50, g will raise an IndexError because the index 50 is not valid for the string a.

But g itself doesn't handle the exception. Notice how there is no try ... except statement in the g function. Since it doesn't handle the exception, it "sends" it to f to see if it can handle it, as you can see in the diagram below:

Since f does know how to handle an IndexError, the situation is handled gracefully and this is the output:

Please enter a valid index

? Note: If f had not handled the exception, the program would have ended abruptly with the default error message for an IndexError.

? Mengakses Butiran Khusus Pengecualian

Pengecualian adalah objek di Python, jadi anda dapat memberikan pengecualian yang dibangkitkan ke pemboleh ubah. Dengan cara ini, anda boleh mencetak keterangan lalai pengecualian dan mengakses argumennya.

Menurut Dokumentasi Python:

Klausa kecuali boleh menentukan pemboleh ubah selepas nama pengecualian . Pemboleh ubah terikat dengan contoh pengecualian dengan argumen yang disimpan di instance.args.

Di sini kita mempunyai contoh (lihat di bawah) adalah kita memberikan contoh ZeroDivisionErrorpemboleh ubah e. Kemudian, kita boleh menggunakan pemboleh ubah ini dalam klausa kecuali untuk mengakses jenis pengecualian, mesejnya, dan argumen.

def divide_integers(): while True: try: a = int(input("Please enter the numerator: ")) b = int(input("Please enter the denominator: ")) print(a / b) # Here we assign the exception to the variable e except ZeroDivisionError as e: print(type(e)) print(e) print(e.args) divide_integers()

Output yang sesuai adalah:

Please enter the numerator: 5 Please enter the denominator: 0 # Type  # Message division by zero # Args ('division by zero',)

? Petua: Jika anda sudah biasa dengan kaedah khas, menurut Python Documentation: "untuk kemudahan, contoh pengecualian menentukan __str__()sehingga argumen dapat dicetak secara langsung tanpa harus merujuk .args."

4️⃣ Sekarang Mari Tambah: Klausa "lain"

The elsefasal adalah pilihan, tetapi ia adalah alat yang hebat kerana ia membolehkan kita melaksanakan kod yang hanya perlu dijalankan jika tiada pengecualian telah dibangkitkan dalam fasal percubaan.

Menurut Dokumentasi Python:

The try... exceptkenyataan mempunyai pilihan fasal lain , yang, apabila hadir, mesti ikut semua kecuali fasal. Ia berguna untuk kod yang mesti dilaksanakan jika klausa percubaan tidak menimbulkan pengecualian.

Berikut adalah contoh penggunaan elseklausa:

def divide_integers(): while True: try: a = int(input("Please enter the numerator: ")) b = int(input("Please enter the denominator: ")) result = a / b except (ZeroDivisionError, ValueError): print("Please enter valid integers. The denominator can't be zero") else: print(result) divide_integers()

Sekiranya tidak ada pengecualian, hasilnya dicetak:

Please enter the numerator: 5 Please enter the denominator: 5 1.0

Tetapi jika terdapat pengecualian, hasilnya tidak dicetak:

Please enter the numerator: 5 Please enter the denominator: 0 Please enter valid integers. The denominator can't be zero

? Petua: Menurut Dokumentasi Python:

Penggunaan elseklausa lebih baik daripada menambahkan kod tambahan pada tryklausa kerana menghindari pengecualian secara tidak sengaja yang tidak dibangkitkan oleh kod yang dilindungi oleh pernyataan tryexcept.

5️⃣ Fasal "akhirnya"

Klausa akhirnya adalah klausa terakhir dalam urutan ini. Itu adalah pilihan , tetapi jika anda memasukkannya, ia mesti menjadi klausa terakhir dalam urutan. The finallyfasal adalah sentiasa dilaksanakan, walaupun pengecualian dibesarkan dalam fasal percubaan.  

Menurut Dokumentasi Python:

Sekiranya finallyklausa hadir, finallyklausa akan dilaksanakan sebagai tugas terakhir sebelum trypernyataan selesai. The finallyfasal berjalan sama ada atau tidak trypernyataan menghasilkan pengecualian.

Klausa akhirnya biasanya digunakan untuk melakukan tindakan "membersihkan" yang harus selalu diselesaikan. Sebagai contoh, jika kita bekerja dengan file dalam klausa percobaan, kita selalu perlu menutup file tersebut, walaupun ada pengecualian ketika kita bekerja dengan data tersebut.

Berikut adalah contoh klausa akhirnya:

def divide_integers(): while True: try: a = int(input("Please enter the numerator: ")) b = int(input("Please enter the denominator: ")) result = a / b except (ZeroDivisionError, ValueError): print("Please enter valid integers. The denominator can't be zero") else: print(result) finally: print("Inside the finally clause") divide_integers()

Ini adalah keluaran apabila tidak ada pengecualian:

Please enter the numerator: 5 Please enter the denominator: 5 1.0 Inside the finally clause

Ini adalah output apabila pengecualian dibangkitkan:

Please enter the numerator: 5 Please enter the denominator: 0 Please enter valid integers. The denominator can't be zero Inside the finally clause

Perhatikan bagaimana finallyklausa selalu berjalan.

❗️Important: remember that the else clause and the finally clause are optional, but if you decide to include both, the finally clause has to be the last clause in the sequence.

6️⃣ Raising Exceptions

Now that you know how to handle exceptions in Python, I would like to share with you this helpful tip: you can also choose when to raise exceptions in your code.

This can be helpful for certain scenarios. Let's see how you can do this:

This line will raise a ValueError with a custom message.

Here we have an example (see below) of a function that prints the value of the items of a list or tuple, or the characters in a string. But you decided that you want the list, tuple, or string to be of length 5. You start the function with an if statement that checks if the length of the argument data is 5. If it isn't, a ValueError exception is raised:

def print_five_items(data): if len(data) != 5: raise ValueError("The argument must have five elements") for item in data: print(item) print_five_items([5, 2])

The output would be:

Traceback (most recent call last): File "", line 122, in  print_five_items([5, 2]) File "", line 117, in print_five_items raise ValueError("The argument must have five elements") ValueError: The argument must have five elements

Notice how the last line displays the descriptive message:

ValueError: The argument must have five elements

You can then choose how to handle the exception with a try ... except statement. You could add an else clause and/or a finally clause. You can customize it to fit your needs.

? Helpful Resources

  • Exceptions
  • Handling Exceptions
  • Defining Clean-up Actions

I hope you enjoyed reading my article and found it helpful. Now you have the necessary tools to handle exceptions in Python and you can use them to your advantage when you write Python code. ? Check out my online courses. You can follow me on Twitter.

⭐️ You may enjoy my other freeCodeCamp /news articles:

  • The @property Decorator in Python: Its Use Cases, Advantages, and Syntax
  • Data Structures 101: Graphs — A Visual Introduction for Beginners
  • Data Structures 101: Arrays — A Visual Introduction for Beginners