GeezerVisonThe World Wide Web, restored to 800 pixels of glory. |
| Home|About|Gaming cabinet|Archives|How it works|Starter sites |
GeezerVison is showing python.github.io — 8. خطاها و استثناها 8. خطاها و استثناها¶تا اینجا پیامهای خطا فقط به صورت کوتاه ذکر شدهاند، اما اگر مثالها را امتحان کرده باشید احتمالاً برخی از آنها را دیدهاید. حداقل دو نوع متمایز از خطا وجود دارد: خطاهای دستوری «syntax errors» و استثناها «exceptions». 8.1. خطاهای دستوری¶خطاهای دستوری، که بهعنوان خطاهای پارسر «parsing errors» نیز شناخته میشوند، شاید رایجترین نوع خطاهایی باشند که هنگام یادگیری پایتون با آنها مواجه میشوید: >>> while True print('Hello world') File "<stdin>", line 1 while True print('Hello world') ^^^^^ SyntaxError: invalid syntax پارسر «parser» خط مشکلدار را تکرار میکند و فلشهای کوچکی را نشان میدهد که به جایی اشاره دارند که خطا در آن شناسایی شده است.
توجه داشته باشید که این همیشه همان جایی نیست که باید اصلاح شود.
در این مثال، خطا در تابع نام پرونده (در مثال ما 8.2. استثنا ها¶حتی اگر یک دستور یا عبارت از نظر دستوری «syntactically» درست باشد، ممکن است هنگام اجرای آن خطایی رخ دهد. خطاهایی که هنگام اجرا شناسایی میشوند «استثنا» «exceptions» نام دارند و الزاماً باعث توقف برنامه نمیشوند؛ بهزودی خواهید آموخت چگونه آنها را در برنامههای پایتون مدیریت کنید. با این حال، بیشتر استثناها در برنامهها مدیریت نمیشوند و به پیامهای خطا ختم میشوند، مانند چیزی که در اینجا نمایش داده شده است: >>> 10 * (1/0) Traceback (most recent call last): File "<stdin>", line 1, in <module> 10 * (1/0) ~^~ ZeroDivisionError: division by zero >>> 4 + spam*3 Traceback (most recent call last): File "<stdin>", line 1, in <module> 4 + spam*3 ^^^^ NameError: name 'spam' is not defined >>> '2' + 2 Traceback (most recent call last): File "<stdin>", line 1, in <module> '2' + 2 ~~~~^~~ TypeError: can only concatenate str (not "int") to str آخرین خط از پیام خطا نشان می دهد که چه اتفاقی افتاده است. استثناها دارای انواع مختلفی هستند و نوع آنها بهعنوان بخشی از پیام چاپ می شود: انواع موجود در مثال عبارتند از بخش باقیماندهی خط، جزئیاتی را بسته به نوع استثنا «exception» و علت وقوع آن ارائه میدهد. بخش قبلی پیام خطا، زمینهای را نشان میدهد که در آن استثنا رخ داده است، بهصورت یک ردگیری پشته «stack traceback». بهطور کلی، این بخش شامل ردگیری پشتهای است که سطرهایی از کد منبع را فهرست میکند؛ با این حال، سطرهایی که از ورودی استاندارد «standard input» خوانده شدهاند در آن نمایش داده نمیشوند. استثناهای توکار فهرستی از استثناهای توکار و معانی آن ها را ارائه می دهد. 8.3. مدیریت استثناها¶امکان نوشتن برنامههایی وجود دارد که برخی از استثناها را مدیریت میکنند. به مثال زیر نگاه کنید که از کاربر ورودی میخواهد تا زمانی که یک عدد صحیح معتبر وارد شود، اما به کاربر اجازه میدهد برنامه را قطع کند (با فشردن Control-C یا هر روشی که سیستمعامل پشتیبانی میکند)؛ توجه داشته باشید که قطع برنامه توسط کاربر با پرتاب استثنای >>> while True: ... try: ... x = int(input("Please enter a number: ")) ... break ... except ValueError: ... print("Oops! That was no valid number. Try again...") ... دستور
یک دستور ... except RuntimeError, TypeError, NameError: ... pass کلاسی که در یک class B(Exception): pass class C(B): pass class D(C): pass for cls in [B, C, D]: try: raise cls() except D: print("D") except C: print("C") except B: print("B") توجه کنید که اگر ترتیب بندهای except برعکس بود (یعنی هنگامی که یک استثنا رخ میدهد، ممکن است مقادیر مرتبطی نیز همراه آن باشد که به آنها آرگومانهای استثنا گفته میشود. وجود و نوع این آرگومانها به نوع استثنا بستگی دارد. بند except میتواند پس از نام استثنا، یک متغیر نیز مشخص کند. این متغیر به نمونهی استثنا (exception instance) نسبت داده میشود که معمولاً دارای ویژگی >>> try: ... raise Exception('spam', 'eggs') ... except Exception as inst: ... print(type(inst)) # the exception type ... print(inst.args) # arguments stored in .args ... print(inst) # __str__ allows args to be printed directly, ... # but may be overridden in exception subclasses ... x, y = inst.args # unpack args ... print('x =', x) ... print('y =', y) ... <class 'Exception'> ('spam', 'eggs') ('spam', 'eggs') x = spam y = eggs خروجی متد
رایجترین الگوی مدیریت import sys try: f = open('myfile.txt') s = f.readline() i = int(s.strip()) except OSError as err: print("OS error:", err) except ValueError: print("Could not convert data to an integer.") except Exception as err: print(f"Unexpected {err=}, {type(err)=}") raise دستور for arg in sys.argv[1:]: try: f = open(arg, 'r') except OSError: print('cannot open', arg) else: print(arg, 'has', len(f.readlines()), 'lines') f.close() استفاده از بند هندلرهای استثنا فقط استثناهایی را که مستقیماً در بخش try رخ میدهند مدیریت نمیکنند، بلکه استثناهایی را که درون توابعی که (حتی بهطور غیرمستقیم) از بخش try فراخوانی شدهاند نیز رخ میدهند، مدیریت میکنند. برای مثال: >>> def this_fails(): ... x = 1/0 ... >>> try: ... this_fails() ... except ZeroDivisionError as err: ... print('Handling run-time error:', err) ... Handling run-time error: division by zero 8.4. پرتاب استثناها¶دستور >>> raise NameError('HiThere') Traceback (most recent call last): File "<stdin>", line 1, in <module> raise NameError('HiThere') NameError: HiThere تنها آرگومان دستور raise ValueError # کوتاهشده برای 'raise ValueError()' اگر فقط لازم است تشخیص دهید که آیا استثنایی رخ داده است یا نه، اما قصد مدیریت آن را ندارید، میتوانید از شکل سادهتری از دستور >>> 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 <module> raise NameError('HiThere') NameError: HiThere 8.5. زنجیرهسازی استثناها¶اگر درون یک بخش >>> try: ... open("database.sqlite") ... except OSError: ... raise RuntimeError("unable to handle error") ... Traceback (most recent call last): File "<stdin>", line 2, in <module> open("database.sqlite") ~~~~^^^^^^^^^^^^^^^^^^^ FileNotFoundError: [Errno 2] No such file or directory: 'database.sqlite' During handling of the above exception, another exception occurred: Traceback (most recent call last): File "<stdin>", line 4, in <module> raise RuntimeError("unable to handle error") RuntimeError: unable to handle error برای نشان دادن این که یک استثنا پیامد مستقیم استثنای دیگری است، دستور # exc must be exception instance or None. raise RuntimeError from exc این قابلیت زمانی مفید است که در حال تبدیل یک استثنا به استثنای دیگری باشید. برای مثال: >>> def func(): ... raise ConnectionError ... >>> try: ... func() ... except ConnectionError as exc: ... raise RuntimeError('Failed to open database') from exc ... Traceback (most recent call last): File "<stdin>", line 2, in <module> func() ~~~~^^ File "<stdin>", line 2, in func ConnectionError The above exception was the direct cause of the following exception: Traceback (most recent call last): File "<stdin>", line 4, in <module> raise RuntimeError('Failed to open database') from exc RuntimeError: Failed to open database همچنین میتوانید با استفاده از الگوی >>> try: ... open('database.sqlite') ... except OSError: ... raise RuntimeError from None ... Traceback (most recent call last): File "<stdin>", line 4, in <module> raise RuntimeError from None RuntimeError برای اطلاعات بیشتر دربارهی سازوکار زنجیرهسازی استثناها، به استثناهای توکار مراجعه کنید. 8.6. استثناهای تعریف شده توسط کاربر¶برنامهها میتوانند با ایجاد یک کلاس استثنای جدید، استثناهای اختصاصی خود را تعریف کنند (برای آشنایی بیشتر با کلاسهای پایتون، به کلاسها مراجعه کنید). معمولاً استثناها باید، بهصورت مستقیم یا غیرمستقیم، از کلاس کلاسهای استثنا میتوانند هر کاری را انجام دهند که سایر کلاسها قادر به انجام آن هستند، اما معمولاً ساده نگه داشته میشوند و اغلب تنها چند ویژگی (attribute) در اختیار میگذارند تا هندلرهای استثنا بتوانند اطلاعات مربوط به خطا را از آنها استخراج کنند. نام بیشتر استثناها به «Error» ختم میشود؛ مشابه شیوهی نامگذاری استثناهای استاندارد. بسیاری از ماژولهای استاندارد، استثناهای اختصاصی خود را برای گزارش خطاهایی که ممکن است در توابعشان رخ دهد تعریف میکنند. 8.7. تعریف عملیات پاکسازی¶دستور >>> try: ... raise KeyboardInterrupt ... finally: ... print('Goodbye, world!') ... Goodbye, world! Traceback (most recent call last): File "<stdin>", line 2, in <module> raise KeyboardInterrupt KeyboardInterrupt اگر بخش
برای مثال: >>> def bool_return(): ... try: ... return True ... finally: ... return False ... >>> bool_return() False یک مثال پیچیدهتر: >>> 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 <module> divide("2", "1") ~~~~~~^^^^^^^^^^ File "<stdin>", line 3, in divide result = x / y ~~^~~ TypeError: unsupported operand type(s) for /: 'str' and 'str' همانطور که میبینید، بخش در برنامههای واقعی، بخش 8.8. عملیات پاکسازی از پیش تعریفشده¶برخی اشیا عملیات پاکسازی استانداردی را تعریف میکنند که باید زمانی انجام شوند که آن شیء دیگر موردنیاز نباشد، صرفنظر از اینکه عملیات مربوط به آن موفق بوده یا شکست خورده باشد. به مثال زیر توجه کنید که تلاش میکند پروندهای را باز کند و محتوای آن را روی صفحه نمایش دهد.: for line in open("myfile.txt"): print(line, end="") مشکل این کد این است که پس از پایان اجرای این بخش، پرونده را برای مدت نامشخصی باز نگه میدارد. در اسکریپتهای ساده این موضوع معمولاً مشکلی ایجاد نمیکند، اما در برنامههای بزرگتر میتواند دردسرساز باشد. دستور with open("myfile.txt") as f: for line in f: print(line, end="") پس از اجرای این دستور، پرونده f همیشه بسته میشود، حتی اگر هنگام پردازش سطرهای پرونده مشکلی رخ داده باشد. اشیایی که مانند پروندهها عملیات پاکسازی از پیش تعریفشده دارند، این موضوع را در مستندات خود ذکر میکنند. 8.9. پرتاب و مدیریت چندین استثنای نامربوط به هم¶گاهی لازم است چندین استثنا که رخ دادهاند بهطور همزمان گزارش شوند. این وضعیت معمولاً در چارچوبهای همروندی (concurrency) پیش میآید؛ جایی که ممکن است چندین وظیفه بهطور موازی شکست بخورند. البته موارد دیگری نیز وجود دارد که در آنها ترجیح داده میشود اجرای برنامه ادامه پیدا کند و چندین خطا جمعآوری شوند، بهجای اینکه با اولین استثنا متوقف شود. استثنای توکار >>> def f(): ... excs = [OSError('error 1'), SystemError('error 2')] ... raise ExceptionGroup('there were problems', excs) ... >>> f() + Exception Group Traceback (most recent call last): | File "<stdin>", line 1, in <module> | f() | ~^^ | File "<stdin>", line 3, in f | raise ExceptionGroup('there were problems', excs) | ExceptionGroup: there were problems (2 sub-exceptions) +-+---------------- 1 ---------------- | OSError: error 1 +---------------- 2 ---------------- | SystemError: error 2 +------------------------------------ >>> try: ... f() ... except Exception as e: ... print(f'caught {type(e)}: {e}') ... caught <class 'ExceptionGroup'>: there were problems (2 sub-exceptions) >>> با استفاده از >>> def f(): ... raise ExceptionGroup( ... "group1", ... [ ... OSError(1), ... SystemError(2), ... ExceptionGroup( ... "group2", ... [ ... OSError(3), ... RecursionError(4) ... ] ... ) ... ] ... ) ... >>> try: ... f() ... except* OSError as e: ... print("There were OSErrors") ... except* SystemError as e: ... print("There were SystemErrors") ... There were OSErrors There were SystemErrors + Exception Group Traceback (most recent call last): | File "<stdin>", line 2, in <module> | f() | ~^^ | File "<stdin>", line 2, in f | raise ExceptionGroup( | ...<12 lines>... | ) | ExceptionGroup: group1 (1 sub-exception) +-+---------------- 1 ---------------- | ExceptionGroup: group2 (1 sub-exception) +-+---------------- 1 ---------------- | RecursionError: 4 +------------------------------------ >>> توجه داشته باشید که استثناهای موجود در یک گروه استثنا باید نمونه (instance) باشند، نه خود کلاسهای استثنا. دلیلش این است که در عمل، این استثناها معمولاً قبلاً توسط برنامه پرتاب و سپس مدیریت شدهاند؛ مطابق الگویی مشابه زیر: >>> excs = [] ... for test in tests: ... try: ... test.run() ... except Exception as e: ... excs.append(e) ... >>> if excs: ... raise ExceptionGroup("Test Failures", excs) ... 8.10. افزودن یادداشت به استثناها¶وقتی یک استثنا برای پرتاب شدن ساخته میشود، معمولاً با اطلاعاتی مقداردهی اولیه میشود که خطای رخداده را توصیف میکنند. بااینحال، گاهی مفید است که پس از مدیریت (catch) شدن استثنا نیز اطلاعات بیشتری به آن افزوده شود. برای این منظور، استثناها متدی به نام >>> try: ... raise TypeError('bad type') ... except Exception as e: ... e.add_note('Add some information') ... e.add_note('Add some more information') ... raise ... Traceback (most recent call last): File "<stdin>", line 2, in <module> raise TypeError('bad type') TypeError: bad type Add some information Add some more information >>> برای مثال، هنگام جمعآوری چند استثنا در یک گروه استثنا، ممکن است بخواهیم اطلاعات زمینهای را به هر خطا اضافه کنیم. در مثال زیر، هر استثنای موجود در گروه یادداشتی دارد که مشخص میکند آن خطا در چه زمانی رخ داده است.: >>> def f(): ... raise OSError('operation failed') ... >>> excs = [] >>> for i in range(3): ... try: ... f() ... except Exception as e: ... e.add_note(f'Happened in Iteration {i+1}') ... excs.append(e) ... >>> raise ExceptionGroup('We have some problems', excs) + Exception Group Traceback (most recent call last): | File "<stdin>", line 1, in <module> | raise ExceptionGroup('We have some problems', excs) | ExceptionGroup: We have some problems (3 sub-exceptions) +-+---------------- 1 ---------------- | Traceback (most recent call last): | File "<stdin>", line 3, in <module> | f() | ~^^ | File "<stdin>", line 2, in f | raise OSError('operation failed') | OSError: operation failed | Happened in Iteration 1 +---------------- 2 ---------------- | Traceback (most recent call last): | File "<stdin>", line 3, in <module> | f() | ~^^ | File "<stdin>", line 2, in f | raise OSError('operation failed') | OSError: operation failed | Happened in Iteration 2 +---------------- 3 ---------------- | Traceback (most recent call last): | File "<stdin>", line 3, in <module> | f() | ~^^ | File "<stdin>", line 2, in f | raise OSError('operation failed') | OSError: operation failed | Happened in Iteration 3 +------------------------------------ >>>
© حق نشر 2001 Python Software Foundation.
این صفحه تحت مجوز بنیاد نرمافزار پایتون نسخه ۲ منتشر شده است. مثالها، دستورالعملها، و سایر کدهای موجود در مستندات همچنین تحت مجوز بدون بند BSD منتشر شدهاند. برای اطلاعات بیشتر به تاریخچه و مجوز مراجعه کنید. بنیاد نرمافزار پایتون یک شرکت غیرانتفاعی است. لطفاً کمک مالی کنید. آخرین بهروزرسانی در نوامبر 12, 2026 (06:19 UTC). آیا اشکالی یافتید؟ ساخته شده با Sphinx 9.1.0. |
| You are visitor 01402503 — GeezerVison does not store the pages you look up. Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required. |