NameError
เกิดขึ้นเวลาที่เรียกใช้ตัวแปรที่ไม่มีอยู่ มักเจอเวลาที่ตั้งใจจะใช้สายอักขระแต่ลืมใส่เครื่องหมายคำพูด
print(สวัสดี) # ได้ NameError: name 'สวัสดี' is not defined
TypeError
เกิดขึ้นเวลาที่ใช้ออบเจ็กต์ผิดชนิด เช่นเวลาคำนวณแล้วเอาข้อมูลที่ไม่ควรจะบวกกันได้มาบวกกัน
print(1+'1') # ได้ TypeError: unsupported operand type(s) for +: 'int' and 'str'
ZeroDivisionError
เกิดขึ้นเวลาที่คำนวณแล้วมีการหาร 0
print(1/0) # ได้ ZeroDivisionError: division by zero
ValueError
เกิดขึ้นเมื่อใส่ค่าที่ไม่ควรจะใส่ลงไปในฟังก์ชัน
import math
math.asin(2) # ได้ ValueError: math domain error
ModuleNotFoundError
เกิดขึ้นเมื่อใช้คำสั่ง import
แล้วมีข้อผิดพลาด เช่นพิมพ์ชื่อมอดูลที่ไม่มีอยู่หรือยังไม่ได้ลงเอาไว้ หรือพิมพ์ชื่อผิด
import mat # ได้ ModuleNotFoundError: No module named 'mat'
IndexError
เกิดขึ้นเวลาที่อ้างอิงข้อมูลชนิดลำดับเช่นลิสต์, ทูเพิล, สายอักขระ แล้วใส่ดัชนีเกินจากค่าที่มีอยู่จริง
a = (0,1,2,3)
print(a[4]) # ได้ IndexError: tuple index out of range
KeyError
เกิดขึ้นเวลาที่เรียกใช้ดิกชันนารีแล้วใส่คีย์ที่ไม่มีอยู่
b = {'ก':1,'ข':2,'ค':3}
b['ง'] # ได้ KeyError: 'ง'
FileNotFoundError
เกิดขึ้นเมื่อเวลาที่เปิดไฟล์แล้วไม่มีไฟล์นั้นอยู่
f = open('xxxx.txt','r',encoding='utf-8') # ได้FileNotFoundError: [Errno 2] No such file or directory: 'xxxx.txt'
IndexError
กับ KeyError
เป็นซับคลาสของ LookupError
print(issubclass(IndexError,LookupError)) # ได้ True
print(issubclass(KeyError,LookupError)) # ได้ True
print(LookupError.__subclasses__()) # ได้ [<class 'IndexError'>, <class 'KeyError'>, <class 'encodings.CodecRegistryError'>]
Exception
คลาสนี้เป็นคลาสรวมของความผิดพลาดพื้นฐานทุกชนิด
print(issubclass(IndexError,Exception)) # ได้ True
print(issubclass(LookupError,Exception)) # ได้ True
print(Exception.__subclasses__()) # ได้คลาสของความผิดพลาดชนิดต่างๆออกมามากมาย
Exception
ยังเป็นซับคลาสของคลาสที่ใหญ่กว่าคือ BaseException
ซึ่งยังรวมความผิดพลาดที่นอกเหนือจากนี้ไป ซึ่งในที่นี้จะยังไม่พูดถึง
print(BaseException.__subclasses__())
[<class 'BaseExceptionGroup'>, <class 'Exception'>, <class 'GeneratorExit'>, <class 'KeyboardInterrupt'>, <class 'SystemExit'>, <class 'asyncio.exceptions.CancelledError'>, <class 'pkg_resources._vendor.more_itertools.more.AbortThread'>]
banchi = 10000
thon = int(input())
khongluea = banchi - thon
print(khongluea)
12000
ก็จะได้ผลเป็น -2000
ซึ่งในความเป็นจริงเป็นไปไม่ได้ที่จะถอนเงินเกินraise
โดยเขียน raise
แล้วตามด้วยชนิดของความผิดพลาด วงเล็บด้วยข้อความที่จะขึ้นเตือน
banchi = 10000
thon = int(input())
khongluea = banchi - thon
if(khongluea<0):
raise ValueError('ยอดเงินในบัญชีไม่พอ')
else:
print(khongluea)
ValueError
ในที่นี้คือชนิดของความผิดพลาดซึ่งเราสามารถกำหนดได้เอง ที่จริงจะกำหนดเป็นอะไรก็ได้ แต่ต้องเป็นชนิดที่เขากำหนดให้แต่แรกValueError
อาจไม่ค่อยถูกต้องนักที่จะใช้ในกรณีแบบนี้ ข้อผิดพลาดที่เราสร้างขึ้นเองส่วนใหญ่แล้วก็ไม่ได้ตรงกับรูปแบบที่มีให้อยู่แล้วแต่แรกException
การสร้างคลาสของความผิดพลาดขึ้นมาใหม่ก็คือสร้างคลาสโดยประกาศให้เป็นซับคลาสของ Exception
class
เหมือนกับคลาสทั่วไป โดยวงเล็บ Exception
ไว้เป็นซูเปอร์คลาส หรือจะใช้ซูเปอร์คลาสเป็นข้อผิดพลาดชนิดอื่นก็ได้เช่นกันMonetaError
ขึ้นมาเตือนเวลาที่เงินไม่พอ
class MonetaError(Exception): # ประกาศคลาส ให้เป็นซับคลาสของ Exception
def __init__(self):
Exception.__init__(self, 'ยอดเงินในบัญชีไม่พอ') # กำหนดข้อความที่แสดงเมื่อมีข้อผิดพลาด
banchi = 10000
thon = int(input())
khongluea = banchi - thon
if(khongluea<0):
raise MonetaError # เรียกใช้คลาส
else:
print(khongluea)
__main__.MonetaError: ยอดเงินในบัญชีไม่พอ
class MonetaError(Exception):
def __init__(self, khat): # เพิ่มตัวแปรมาตัวหนึ่ง คือเงินที่ขาด
Exception.__init__(self, 'ยอดเงินในบัญชีไม่พอ ขาดไป %d'%khat) #นำตัวแปรที่เพ่ิมมาแสดงผลด้วย
banchi = 10000
thon = int(input())
khongluea = banchi - thon
if(khongluea<0):
raise MonetaError(-khongluea) # ใส่ค่าเงินที่ติดลบเกินไป
else:
print(khongluea)
__main__.MonetaError: ยอดเงินในบัญชีไม่พอ ขาดไป 2000
try
และ except
f = open('xxxx.txt','r',encoding='utf-8')
print(f.read())
f.close()
หากไฟล์ xxxx.txt ไม่มีตัวตนอยู่จะได้ว่า
FileNotFoundError: [Errno 2] No such file or directory: 'xxxx.txt'
try
และ except
ดังนี้
try:
f = open('xxxx.txt','r',encoding='utf-8')
print(f.read())
f.close()
except:
print('เปิดไฟล์ไม่สำเร็จ')
ผลลัพธ์
เปิดไฟล์ไม่สำเร็จ
except
f = open('xxxx.txt','w',encoding='utf-8')
f.write('xxxxxxxx')
f.close()
xxxxxxxx
except
จะไม่ถูกอ่านเมื่อไม่มีการขัดข้องอะไรเกิดขึ้นtry
และ except
นี้ว่าไปแล้วก็คล้าย if
และ else
แต่ต่างกันตรงที่ว่า try
และ except
ต้องอยู่คู่กันตลอด จะละ except
ทิ้งไม่ได้0
หรืออาจใช้ pass
ก็ได้ เช่น
for i in range(-3,4):
try:
print(6/i)
except:
0
-2.0
-3.0
-6.0
6.0
3.0
2.0
for
ทั้งหมด ๗ ครั้ง แต่มีเลขออกมาแค่ ๖ ตัว เพราะเมื่อ i
เท่ากับ 0
จะไม่เกิดอะไรขึ้น ถูกข้ามไปเลยexcept
ถ้าเราเขียนแค่ except
เฉยๆก็จะมีการทำไม่ว่าจะเกิดความผิดพลาดแบบไหนก็ตาม แต่เราสามารถจำกัดเงื่อนไขของความผิดพลาดไปได้ด้วยการใส่ชนิดของความผิดพลาด ไว้ข้างหลังtry:
f = open('xxxxxxx.txt','r',encoding='utf-8')
print(f.read())
f.close()
except ValueError:
print('เปิดไฟล์ไม่สำเร็จ')
ValueError
เข้ามาข้างหลัง except
แต่ผลที่ได้ก็คือความผิดพลาดยังคงเกิดขึ้นมาตามปกติFileNotFoundError
ไม่ใช่ ValueError
การเขียน ValueError
ไว้ข้างหลัง except
แบบนี้จะทำให้มันทำงานเฉพาะเมื่อมีข้อผิดพลาดแบบ ValueError
เท่านั้น ดังนั้น except
จึงไม่ทำงานในกรณีนี้except
ที่มีเงื่อนไขต่างกันได้ในเวลาเดียวกัน
try:
f = open('xxxxxxx.txt','r',encoding='utf-8')
print(f.read())
f.close()
except ValueError:
print('ค่าผิดพลาด')
except FileNotFoundError:
print('เปิดไฟล์ไม่สำเร็จ')
except
อันสุดท้ายอาจไม่ต้องเขียนชนิดลงไปก็ได้ ซึ่งมันจะทำงานเมื่อมีข้อผิดพลาดนอกเหนือจากที่ระบุข้างต้นมาแล้วทั้งหมด เช่น
try:
print(1/0)
except ValueError:
print('ค่าผิดพลาด')
except FileNotFoundError:
print('เปิดไฟล์ไม่สำเร็จ')
except:
print('เกิดปัญหาบางประการ')
raise
ในโครงสร้าง try
ก็จะทำให้เกิดการทำอะไรใน except
ได้เช่นกัน
try:
raise ValueError
except ValueError:
print('ค่าผิดพลาด')
class BakaError(Exception):
def __init__(self):
Exception.__init__(self)
try:
raise BakaError
except BakaError:
print('baka baka baka')
try
และ except
แล้วเกิดข้อผิดพลาดขึ้นใน try
จะไม่มีการแสดงข้อความที่เตือนถึงข้อผิดพลาด แต่จะทำเหมือนไม่มีอะไรเกิดขึ้นเลยas
ไปด้านหลังชนิดของข้อผิดพลาดซึ่งตามหลัง except
อีกที แล้วหลัง as
ใส่ตัวแปรที่ต้องการให้มารับออบเจ็กต์ของความผิดพลาด
import math
try:
math.acos(2)
except Exception as er:
print(type(er)) # ได้ <class 'ValueError'>
print(er) # ได้ math domain error
er
จะเก็บออบเจ็กต์ของความผิดพลาดเอาไว้ พอใช้ type
ก็จะแสดงคลาสของความผิดพลาด ในที่นี้คือ ValueError
print
กับออบเจ็กต์ของความผิดพลาดจะเป็นการแสดงข้อความเตือนที่ผิดพลาด,
แทน as
try
สามารถใช้ซ้อนกันได้ เช่น
try:
try:
1/0
except:
print('มีข้อผิดพลาดข้างใน')
except:
print('มีข้อผิดพลาดข้างนอก')
มีข้อผิดพลาดข้างใน
except
ด้านใน แต่มันก็ทำให้โปรแกรมทำงานต่อไปตามปกติ ดังนั้น except
ด้านนอกก็จะถูกมองข้ามไปexcept
ข้างนอกด้วยก็อาจจะใส่ raise
ภายใน except
ด้านในอีกที
try:
try:
1/0
except:
print('มีข้อผิดพลาดข้างใน')
raise Exception
except:
print('มีข้อผิดพลาดข้างนอก')
มีข้อผิดพลาดข้างใน
มีข้อผิดพลาดข้างนอก
try
except
สามารถต่อด้วย else
ได้ด้วย โดยจะตรงข้ามกับ except
คือเป็นคำสั่งที่จะทำเมื่อไม่มีการขัดข้องเกิดขึ้นเท่านั้นtry:
print(1/0) # ขัดข้อง
except:
print(2) # ทำงาน
else:
print(3) # ไม่ทำงาน
2
try:
print(1) # ไม่ขัดข้อง
except:
print(2) # ไม่ทำงาน
else:
print(3) # ทำงาน
1
3
try
, except
และ else
แล้วยังมี finally
ซึ่งใช้น้อยกว่า จึงขอแยกไปเขียนเป็นเนื้อหาเสริมในอีกหน้าติดตามอัปเดตของบล็อกได้ที่แฟนเพจ