شنبه ۲۹ دي ۱۴۰۳
Tut24 آموزش برنامه نویسی و مجله تخصصی فناوری ورود/عضویت

آموزش پایتون - مدیریت استثناء‌ها

پایتون دو ویژگی بسیار مهم را فراهم می‌کند که به ما اجازه می‌دهد هر گونه خطای غیرمنتظره در برنامه‌ها را کنترل کرده و قابلیت اشکال‌زدایی را به آنها اضافه نماییم.

  • مدیریت استثناء‌ها (Exception Handling)   در این قسمت، لیستی از استثناء‌های استاندارد در پایتون در اختیار شما قرار دارد، که به طور خودکار در برنامه‌ها برای کنترل خطاها مورد استفاده قرار می‌گیرند.

  • تأییدها (Assertions) -تأییدها ابزاری هستند که در پایتون برای اطمینان از صحت شرایط و فرضیات در برنامه‌ها استفاده می‌شوند. این بخش از آموزش شامل توضیحاتی درباره استفاده از تأییدها و نحوه پیاده‌سازی آنها در پایتون خواهد بود.
     

لیستی از استثناء‌های استاندارد:

شماره نام استثناء و توضیحات
1

استثناء (Exception)

کلاس پایه برای همه استثناء‌ها

2

متوقف‌شدن (StopIteration)

 وقتی متد()next یک تکرارکننده به هیچ موردی اشاره نمی‌کند، یک استثناء به نام StopIteration ایجاد می‌شود. این استثناء نشان‌دهنده اتمام پیمایش مجموعه داده‌ای است که توسط تکرارکننده ارائه می‌شود. این مکانیزم استثنائی به برنامه‌نویس اجازه می‌دهد که بفهمد که تمام موارد در تکرارکننده به پایان رسیده‌اند و دیگر داده‌ای برای پردازش وجود ندارد. این مفهوم به ویژه در حلقه‌های for که بر روی تکرارکننده‌ها (مثل لیست‌ها، تاپل‌ها و فایل‌ها) اجرا می‌شوند، بسیار مهم است.

3

خروج سیستم (SystemExit)

توسط تابع()sys.exit ایجاد می‌شود.

4

خطای استاندارد (StandardError)

کلاس پایه برای همه استثناء‌های داخلی به جز StopIteration و SystemExit

5

خطای عددی (ArithmeticError)

کلاس پایه برای همه خطاهای محاسبات عددی

6

خطای سرریز (OverflowError)

زمانی که یک محاسبه از حداکثر مقدار برای یک نوع عددی فراتر می‌رود، ایجاد می‌شود.

7

خطای اعشاری (FloatingPointError)

زمانی که یک محاسبه اعشاری ناموفق است، ایجاد می‌شود.

8

خطای تقسیم بر صفر (ZeroDivisionError)

زمانی که تقسیم یا باقی‌مانده بر صفر برای همه انواع عددی اتفاق می‌افتد، ایجاد می‌شود.

9

خطای تأیید (AssertionError)

زمانی که تأیید انجام نمی‌شود، ایجاد می‌شود.

10

خطای ویژگی (AttributeError)

زمانی که ارجاع به ویژگی یا اختصاص ویژگی ناموفق است، ایجاد می‌شود.

11

خطای EOF (EOFError)

زمانی که هیچ ورودی از تابع () raw_input یا ()input و حالت پایانی فایل را نمی‌توان یافت، ایجاد می‌شود.

12

خطای وارد (ImportError)

زمانی که یک عبارت وارد کردن ناموفق است، ایجاد می‌شود.

13

خطای وقفه صفحه‌کلید (KeyboardInterrupt)

زمانی که کاربر اجرای برنامه را وقفه می‌دهد، معمولاً با فشردن Ctrl+c، ایجاد می‌شود.

14

خطای جستجو (LookupError)

کلاس پایه برای همه خطاهای جستجو

15

خطای اندیس (IndexError)

زمانی که یک اندیس در یک توالی پیدا نمی‌شود، ایجاد می‌شود.

16

خطای کلید (KeyError)

زمانی که کلید مشخص شده در دیکشنری یافت نمی‌شود، ایجاد می‌شود.

17

خطای نام (NameError)

زمانی که یک شناسه در فضای نامی محلی یا سراسری یافت نمی‌شود، ایجاد می‌شود.

18

خطای متغیر محلی نامرتبط (UnboundLocalError)

زمانی که سعی در دسترسی به یک متغیر محلی در یک تابع یا متد انجام می‌شود، اما به آن مقدار اختصاص داده نشده است، ایجاد می‌شود.

19

خطای محیط (EnvironmentError)

کلاس پایه برای همه استثناء‌هایی که خارج از محیط پایتون رخ می‌دهند

20

خطای ورودی/خروجی (IOError)

زمانی که یک عملیات ورودی/خروجی شکست می‌خورد، مانند دستور print یا تابع open() زمانی که سعی در باز کردن یک فایلی که وجود ندارد، انجام می‌شود.

21

خطای ورودی/خروجی (IOError)

زمانی که خطاهای مربوط به سیستم‌عامل رخ می‌دهند.

22

خطای نحو (SyntaxError)

زمانی که یک خطا در نحو پایتون وجود دارد، ایجاد می‌شود.

23

خطای تورفتگی (IndentationError)

زمانی که تورفتگی به درستی مشخص نشده است، ایجاد می‌شود.

24

خطای سیستم (SystemError)

زمانی که مفسر یک مشکل داخلی پیدا می‌کند، اما در صورت بروز این خطا، مفسر پایتون خارج نمی‌شود.

25

خروج سیستم (SystemExit)

زمانی که مفسر پایتون با استفاده از تابع sys.exit() خاتمه می‌یابد. اگر در کد کنترل نشود، باعث خروج مفسر می‌شود.

26

خطای نوع داده (TypeError)

زمانی که یک عملیات یا تابع برای نوع داده مشخص نامعتبر است، ایجاد می‌شود.

27

خطای ارزش (ValueError)

زمانی که یک عملیات یا تابع برای یک مقدار ، نامعتبر است، ایجاد می‌شود.

28

خطای عدم پیاده‌سازی (NotImplementedError)

زمانی که یک متد در یک کلاس پیاده‌سازی نشده است، ایجاد می‌شود.

این فقط چند نمونه از استثناء‌های موجود در زبان برنامه‌نویسی پایتون است. برنامه‌نویسان می‌توانند خطاهای سفارشی خود را با استفاده از کلاس استثناء پایتون تعریف کنند و آن‌ها را در برنامه خود استفاده کنند.

Assertion در پایتون

 تأییدها (Assertion) در پایتون، یک ابزار برای اطمینان از درستی فرضیاتی که در برنامه‌تان دارید و بررسی صحت آنها در حالت‌های آزمون (تست) فراهم می‌کند. وقتی شما از تأییدها استفاده می‌کنید، در واقع یک دستور می نویسید که یک شرط باید برآورده شود، و اگر شرط برآورده نشود، یک خطای AssertionError ایجاد می‌شود

 تأییدها (Assertions) را می‌توان به عنوان یک نوعی دستور "بروزخطا-اگر-نه" در نظر گرفت. این به این معناست که شما یک شرط را بررسی می‌کنید و اگر آن شرط نادرست باشد، یک خطا را ایجاد می‌کنید.

تأییدها  توسط دستور assert انجام می‌شوند که یکی از جدیدترین کلمه های کلیدی پایتون است که در نسخه 1.5 معرفی شده است.

برنامه‌نویسان اغلب تأییدها  را در ابتدای یک تابع قرار می‌دهند تا ورودی‌های معتبر را بررسی کنند .

دستور assert

زمانی که برنامه به یک دستور assert می‌رسد، پایتون ابتدا عبارت موجود در دستور assert را ارزیابی می‌کند. اگر این عبارت به صورت True (درست) ارزیابی شود، برنامه به صورت عادی ادامه پیدا می‌کند و هیچ اتفاقی نمی‌افتد.

دستور assert را می‌توان به شکل زیر نوشت:

assert Expression[, Arguments]

زمانی که یک تأیید (assertion) شکست می‌خورد و یک استثناء AssertionError ایجاد می‌شود، محتوای عبارت تأییدها (که به عنوان ArgumentExpression شناخته می‌شود) به عنوان آرگومان برای استثناء AssertionError استفاده می‌شود. این محتوا معمولاً یک پیام توضیحی است که شما در دستور assert نوشته‌اید.

مثال

اینجا یک تابع است که یک دما را از درجه کلوین به درجه فارنهایت تبدیل می‌کند. از آنجایی که صفر درجه کلوین به سرمایی بی‌نهایت نزدیک است، تابع در صورت دیدن یک دمای منفی متوقف می‌شود −

def KelvinToFahrenheit(Temperature):
   assert (Temperature >= 0),"Colder than absolute zero!"
   return ((Temperature-273)*1.8)+32
print KelvinToFahrenheit(273)
print int(KelvinToFahrenheit(505.78))
print KelvinToFahrenheit(-5)

زمانی که کد بالا اجرا می‌شود، نتیجه زیر را تولید می‌کند −

32.0
451
Traceback (most recent call last):
File "test.py", line 9, in <module>
print KelvinToFahrenheit(-5)
File "test.py", line 4, in KelvinToFahrenheit
assert (Temperature >= 0),"Colder than absolute zero!"
AssertionError: Colder than absolute zero!

استثناء چیست

استثناء رویدادی است که در حین اجرای یک برنامه رخ می‌دهد و جریان طبیعی دستورات برنامه را به هم می‌ریزد. به طور کلی، وقتی یک اسکریپت پایتون با موقعیتی مواجه می‌شود که نمی‌تواند با آن کنار بیاید، یک استثناء برمی‌گرداند. استثناء یک ابجکت پایتونی است که خطایی را نمایندگی می‌کند.

زمانی که یک اسکریپت پایتون یک استثناء برمی‌گرداند، باید یا فوراً استثناء را کنترل کند و در غیر اینصورت برنامه را متوقف و خاتمه دهد.

کنترل استثناء

اگر کد مشکوکی دارید که ممکن است یک استثناء برگرداند، می‌توانید برنامه خود را در برابر آن محافظت کنید. برای این کار کد مشکوک را در یک بلوک try: قرار دهید. بعد از بلوک try:، یک دستور except: را قرار دهید و سپس یک بلوک کد قرار دهید که مشکل را برطرف کند.

ساختار دستوری

در ادامه، ساختار ساده‌ای از بلوک‌های try...except...else را مشاهده می‌کنید −

try:
   You do your operations here;
   ......................
except ExceptionI:
   If there is ExceptionI, then execute this block.
except ExceptionII:
   If there is ExceptionII, then execute this block.
   ......................
else:
   If there is no exception then execute this block. 

در ادامه چند نکته مهم درباره ساختار فوق آورده شده است −

  • یک دستور try می‌تواند شامل چند دستور except باشد. این موضوع زمانی که بلوک try شامل دستورهایی است که ممکن است انواع مختلفی از استثناء را تولید کند، مفید است.

  • همچنین می‌توانید یک بلوک except عمومی را ارائه دهید که هر نوع استثناء را کنترل کند.

  • پس از بلوک(های) except، می‌توانید یک بلوک else قرار دهید. کد موجود در بلوک else اجرا می‌شود اگر کد موجود در بلوک try هیچ استثنایی را ایجاد نکند.

  • بلوک else مکان مناسبی برای قرار دادن کدهایی است که به حفاظت بلوک try نیاز ندارند.

مثال

این مثال یک فایل را باز می‌کند، محتوا را در فایل می‌نویسد و به طور کامل و بدون مشکل خارج می‌شود −

try:
   fh = open("testfile", "w")
   fh.write("This is my test file for exception handling!!")
except IOError:
   print "Error: can\'t find file or read data"
else:
   print "Written content in the file successfully"
   fh.close()

این کد نتیجه زیر را تولید می‌کند −

Written content in the file successfully

مثال

این مثال سعی می‌کند یک فایل را با دسترسی نوشتن باز کند، بنابراین یک استثناء (exception) رخ می‌دهد −

try:
   fh = open("testfile", "r")
   fh.write("This is my test file for exception handling!!")
except IOError:
   print "Error: can\'t find file or read data"
else:
   print "Written content in the file successfully"

این عبارت نتیجه زیر را تولید می‌کند −

Error: can't find file or read data

بند except بدون تعریف استثنا

شما همچنین می‌توانید از دستور except بدون تعریف استثنا استفاده کنید به شرح زیر −

try:
   You do your operations here;
   ......................
except:
   If there is any exception, then execute this block.
   ......................
else:
   If there is no exception then execute this block. 

این نوع دستور try-except همه استثناهایی را که رخ می‌دهد، شامل می‌شود. استفاده از این نوع بیانیه try-except به عنوان یک شیوه برنامه‌نویسی خوب مورد توصیه قرار نمی‌گیرد، زیرا همه استثناها را شامل می‌شود اما برنامه‌نویس را مجبور نمی‌کند علت اصلی مشکلی که ممکن است رخ دهد را شناسایی کند.

بند except با چند استثنا

شما همچنین می‌توانید از همان بیانیه except استفاده کنید تا چند استثنا را به شکل زیر کنترل کنید −

try:
   You do your operations here;
   ......................
except(Exception1[, Exception2[,...ExceptionN]]]):
   If there is any exception from the given exception list, 
   then execute this block.
   ......................
else:
   If there is no exception then execute this block. 

کلمه کلیدی try-finally

می‌توانید یک بلوک finally: را همراه با یک بلوک try: استفاده کنید. بلوک finally یک مکان است برای قرار دادن هر کدی که باید اجرا شود، بدون توجه به اینکه بلوک try با یک استثناء مواجه شده باشد یا نه. ساختار بیانیه try-finally به این صورت است:

try:
   You do your operations here;
   ......................
   Due to any exception, this may be skipped.
finally:
   This would always be executed.
   ......................

شما نمی‌توانید بلوک else را همراه با یک بلوک finally استفاده کنید.

مثال

try:
   fh = open("testfile", "w")
   fh.write("This is my test file for exception handling!!")
finally:
   print "Error: can\'t find file or read data"

اگر شما دسترسی لازم برای باز کردن فایل در حالت نوشتن را نداشته باشید، در این صورت نتیجه زیر را به دست خواهید آورد −

Error: can't find file or read data

مثال مشابه می‌تواند به صورت زیر نوشته شود −

try:
   fh = open("testfile", "w")
   try:
      fh.write("This is my test file for exception handling!!")
   finally:
      print "Going to close the file"
      fh.close()
except IOError:
   print "Error: can\'t find file or read data"

وقتی یک استثناء در بلوک try ایجاد می‌شود، اجرا به صورت فوری به بلوک finally منتقل می‌شود. پس از اجرای تمام دستورات در بلوک finally، دوباره برمی‌گردد و در صورت وجوداستثنا در دستور except در لایه‌ی بالاتر از دستور try-except که در آن قرار دارد، کنترل می‌شود.

آرگومان یک استثناء

یک استثناء می‌تواند شامل یک آرگومان باشد . این آرگومان مقداری است که اطلاعات اضافی درباره‌ی مشکل را ارائه می‌دهد. محتوای آرگومان بستگی به نوع استثناء دارد. شما می‌توانید آرگومان استثناء را با ارائه یک متغیر در بخش except به شکل زیر ثبت کنید −

try:
   You do your operations here;
   ......................
except ExceptionType, Argument:
   You can print value of Argument here...

اگر کد را برای کنترل یک استثناء تنها بنویسید، می‌توانید یک متغیر را در بیانیه except پس از نام استثناء قرار دهید. اگر شما قصد دارید چند استثناء را طرح کنید، می‌توانید یک متغیر را پس از تاپل استثناء قرار دهید.

این متغیر اغلب مقدار استثناء را دریافت می‌کند که بیشتر اطلاعات علت استثناء را شامل می‌شود. این متغیر می‌تواند یک مقدار تکی یا چند مقدار را در قالب یک تاپل دریافت کند. این تاپل به طور معمول شامل رشته‌ی خطا، شماره‌ی خطا و محل خطا است.

مثال

مثال زیر نمونه‌ای برای یک استثناء تکی است −

# Define a function here.
def temp_convert(var):
   try:
      return int(var)
   except ValueError, Argument:
      print "The argument does not contain numbers\n", Argument

# Call above function here.
temp_convert("xyz");

این کد نتیجه زیر را تولید می‌کند −

The argument does not contain numbers
invalid literal for int() with base 10: 'xyz'

دستور raise

شما می‌توانید با استفاده از دستور raise، استثناء را به چندین روش تولید کنید. سینتکس عمومی برای دستور raise به شکل زیر است.

raise [Exception [, args [, traceback]]]

در اینجا، Exception نوع استثناء است (برای مثال، NameError) و argument مقداری برای آرگومان استثناء است. آرگومان اختیاری است؛ اگر ارائه نشود، مقدار آرگومان استثناء None است.

آرگومان نهایی، traceback نیز اختیاری است (و در عمل بسیار کم استفاده می‌شود) و در صورت وجود، اشیاء traceback استفاده شده برای استثناء می باشد.

مثال

یک استثناء می‌تواند یک رشته، یک کلاس یا یک شیء باشد. بیشتر استثناءهایی که هسته‌ی پایتون ایجاد می‌کند، کلاس‌ها هستند که آرگومان آن‌ها نمونه‌ای از کلاس است. تعریف استثناء‌های جدید کار آسانی است و می‌تواند به شکل زیر انجام شود 

def functionName( level ):
   if level < 1:
      raise "Invalid level!", level
      # The code below to this would not be executed
      # if we raise the exception

به عنوان مثال، برای گرفتن استثناء بالا، باید بخش except را به شکل زیر بنویسیم −

try:
   Business Logic here...
except "Invalid level!":
   Exception handling here...
else:
   Rest of the code here...

استثناء‌های تعریف‌شده توسط کاربر

پایتون همچنین به شما امکان می‌دهد استثناء‌های خود را با ارث‌بری از استثناء‌های استاندارد داخلی ساخته شده، ایجاد کنید.

اینجا یک مثال مربوط به RuntimeError وجود دارد. در اینجا، یک کلاس ایجاد می‌شود که از کلاس RuntimeError به عنوان زیرکلاس مشتق شده است. این کار زمانی مفید است که نیاز دارید اطلاعات مشخص‌تری را هنگام گرفتن یک استثناء نشان دهید.

در بلوک try، استثناء تعریف‌شده توسط کاربر ایجاد می شود و در بلوک except دریافت  می‌شود. متغیر e برای ایجاد یک نمونه از کلاس Networkerror استفاده می‌شود.

class Networkerror(RuntimeError):
   def __init__(self, arg):
      self.args = arg

پس از تعریف کلاس بالا، می‌توانید استثناء را به شکل زیر بنویسید :

try:
   raise Networkerror("Bad hostname")
except Networkerror,e:
   print e.args