درک traceback پایتون

امیرحسین بیگدلو 5 ماه قبل

هنگامی که یک Exception در کد شما رخ میدهد، پایتون یک traceback را چاپ می کند. اگر برای اولین بار آن را می بینید یا نمی دانید چه چیزی به شما می گوید، خروجی traceback می تواند کمی زیاد باشد. اما traceback پایتون دارای اطلاعات زیادی است که می تواند به شما در تشخیص و رفع دلیل استثنا در کد شما کمک کند. درک اینکه چه اطلاعاتی در یک traceback پایتون هست برای تبدیل شدن به یک برنامه نویس بهتر پایتون ضروری است.

 

# Traceback پایتون چیست؟

Traceback گزارشی است که شامل فراخوانی های عملکردی است که در یک نقطه خاص در کد شما ایجاد شده است. Tracebacks با نام های زیادی شناخته می شود، از جمله stack trace ، stack traceback ، backtrace و شاید دیگران. در پایتون، واژه مورد استفاده traceback است.

 

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

# example.py
def greet(someone):
    print('Hello, ' + someon)

greet('Chad')

 

در اینجا ، greet() با پارامتر someone فراخوانی میشود. با این حال، در greet()، آن نام متغیر با غلط املایی someon استفاده شده است.

 

توجه: این آموزش فرض می کند که شما Exception پایتون را درک می کنید. اگر نمیدانید، بهتر است ویدیو آموزش مدیریت خطا در پایتون را ببینید.

 

هنگامی که این برنامه را اجرا می کنید ، traceback زیر را دریافت خواهید کرد:

$ python example.py
Traceback (most recent call last):
  File "/path/to/example.py", line 4, in <module>
    greet('Chad')
  File "/path/to/example.py", line 2, in greet
    print('Hello, ' + someon)
NameError: name 'someon' is not defined

 

این خروجی traceback دارای تمام اطلاعاتی است که برای تشخیص مشکل به آن نیاز دارید. خط آخر خروجی traceback به شما می گوید که چه نوع استثنایی همراه با برخی اطلاعات مربوط به آن استثنا مطرح شده است. خطوط قبلی traceback به کدی اشاره می کند که منجر به ایجاد استثنا شد.

 

در traceback بالا، استثنا یک NameError بود، به این معنی که اشاره ای به نام (متغیر، فانکشن، کلاس) وجود دارد که تعریف نشده است. در این مورد، نام مورد اشاره someon است.

 

خط آخر در این مورد دارای اطلاعات کافی است تا به شما در رفع مشکل کمک کند. جستجوی کد نام someon، که غلط املایی است، شما را در مسیر درست نشان می دهد. اما اغلب، کد شما بسیار پیچیده تر است.

 

مقاله پیشنهادی: چقدر زمان میبرد تا پایتون را یاد بگیریم؟

 

# چطور یک Traceback پایتون را بخوانیم؟

وقتی سعی می کنید دلیل ایجاد استثنا در کد خود را مشخص کنید، traceback پایتون حاوی اطلاعات مفیدی است. در این بخش، برای پی بردن به جزئیات مختلف اطلاعات موجود در یک traceback، ما tracebackهای مختلف را با هم میبینیم.

 

+ بررسی traceback پایتون

چندین بخش برای هر traceback پایتون وجود دارد که مهم هستند. نمودار زیر قسمت های مختلف را برجسته می کند:

بررسی traceback پایتون

 

در پایتون ، بهتر است traceback را از پایین به بالا بخوانید:

 

1. جعبه آبی: آخرین خط traceback خط پیام خطا است. این شامل نام استثنایی است که مطرح شده است.

 

2. جعبه سبز: بعد از نام استثنا پیام خطا است. این پیام معمولاً حاوی اطلاعات مفیدی برای درک دلیل ایجاد استثنا است.

 

3. جعبه زرد: در ادامه traceback، بخش‌های مختلف ارور هستند که از بالا به پایین و از آخرین ارور به اولین ارور چیده شده‌اند. هر بخش دارای دو قسمت است که قسمت اول اطلاعاتی شامل نام فایل، شماره خط فایل، نام ماژول و تمام مواردی که کد در کجا پیدا میشود.

 

4. زیرخط قرمز: قسمت دوم که کدی که واقعا باعث ارور شده را نشان میدهد.

 

 

هنگام اجرای کد در خط فرمان و اجرای کد در REPL، بین خروجی traceback چند تفاوت وجود دارد. در زیر، همان کد مربوط به بخش قبلی است که در REPL اجرا شده است و خروجی traceback حاصله:

>>> def greet(someone):
...   print('Hello, ' + someon)
... 
>>> greet('Chad')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in greet
NameError: name 'someon' is not defined

 

توجه داشته باشید که به جای نام فایل، "<stdin>" را دریافت می کنید. این امر از آنجا که کد را از طریق ورودی استاندارد وارد کرده اید منطقی است. همچنین خطوط اجرا شده کد در traceback نمایش داده نمی شوند.

 

مقاله پیشنهادی: دوره های آموزش پروژه محور و پیشرفته پایتون

 

+ کار با یک traceback خاص

کار با یک traceback به شما درک درستی خواهد داد که چه اطلاعاتی از طریق traceback در دسترس است.

 

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

# greetings.py
def who_to_greet(person):
    return person if person else input('Greet who? ')

def greet(someone, greeting='Hello'):
    print(greeting + ', ' + who_to_greet(someone))

def greet_many(people):
    for person in people:
        try:
            greet(person)
        except Exception:
            print('hi, ' + person)

 

در اینجا، who_to_greet () یک مقدار، person را می گیرد و یا آن را برمی گرداند یا به جای آن یک مقدار درخواست میکند که آن را برگرداند.

 

سپس، greet() نامی را که باید به آن احوالپرسی کنید، someone، و یک جمله تبریک اختیاری می گیرد و print() را صدا میزند. who_to_greet () نیز با مقدار someone که وارد شده است فراخوانی می شود.

 

در نهایت ، greet_many() روی لیست افراد تکرار می شود و greet() را صدا می کند. اگر استثنائی با فراخوانی greet() وجود داشته باشد، یک سلام ساده پشتیبان چاپ می شود.

 

این کد هیچ باگی ندارد و تا زمانی که ورودی مناسب ارائه شود، یک استثنا اجرا نمیشود.

 

اگر در آخر کد بالا فانکشن greet را صدا بزنید و یک ورودی غیر منتظره را ارسال کنید مثلا greet('Chad', greting='Yo') ، آنوقت traceback زیر را دریافت میکنید:

$ python example.py
Traceback (most recent call last):
  File "/path/to/greetings.py", line 19, in <module>
    greet('Chad', greting='Yo')
TypeError: greet() got an unexpected keyword argument 'greting'

 

یکبار دیگر، با traceback پایتون، بهتر است به پایین حرکت کرده و بالا برید. با شروع از خط آخر traceback، می توانید ببینید که استثنا یک TypeError بود. پیامهایی که از نوع استثنا پیروی می کنند، بعد از دونقطه، اطلاعات فوق العاده ای در اختیار شما قرار میگیرد. به شما می گوید که greet() با آرگومان کلمه کلیدی که انتظار آن را نداشت فراخوانی شد. نام آرگومان ناشناخته نیز به شما داده می شود: greting.

 

با حرکت به سمت بالا، می توانید خطی را مشاهده کنید که منجر به استثنا شد. در این مورد، این greet() است که ما به کد بالا اضافه کردیم.

 

خط بعدی مسیر فایلی را که کد در آن وجود دارد، شماره خط آن فایل را که کد در آن یافت می شود و در کدام ماژول قرار می دهد به شما می دهد. در این مورد، کد ما از هیچ ماژول پایتون دیگری استفاده نمی کند، ما فقط <module> را در اینجا می بینیم، به این معنی که این فایل در حال اجرا است.

 

با یک فایل متفاوت و ورودی متفاوت، می توانید traceback را ببینید که واقعاً شما را در جهت درست یافتن مشکل راهنمایی می کند. اگر در حال پیگیری هستید، فراخوان greet() را از قسمت پایین greeting.py بردارید و فایل زیر را به دایرکتوری خود اضافه کنید:

# example.py
from greetings import greet

greet(1)

 

در اینجا شما یک فایل پایتون دیگر راه اندازی کرده اید که ماژول قبلی شما، greetings.py را وارد کرده و از greet() آن استفاده می کند. اگر اکنون example.py را اجرا کنید، چه اتفاقی می افتد:

$ python example.py
Traceback (most recent call last):
  File "/path/to/example.py", line 3, in <module>
    greet(1)
  File "/path/to/greetings.py", line 5, in greet
    print(greeting + ', ' + who_to_greet(someone))
TypeError: must be str, not int

 

استثنائی که در این مورد مطرح می شود دوباره TypeError است، اما این بار پیام کمی مفیدتر است. به شما می گوید که در جایی از کد انتظار می رفت که با یک رشته کار کند، اما یک عدد صحیح داده شد.

 

با حرکت به سمت بالا، خط کد اجرا شده را مشاهده می کنید. سپس فایل و شماره خط کد. این بار اما به جای <module>، نام تابع در حال اجرا را دریافت می کنیم ، greet()

 

به سمت خط بعدی کد اجرا شده، می بینیم که فراخوانی مشکل ساز greet() ما به دلیل عدد صحیح بوده.

 

گاهی اوقات پس از مطرح شدن یک استثنا، مقدار دیگری از کد آن استثنا را می گیرد و منجر به یک استثنا دیگر می شود. در این شرایط، پایتون همه ردپایهای استثنائی را به ترتیبی که دریافت کرده است، نمایش می دهد، و بار دیگر به جدیدترین ردیابی استثنایی می انجامد.

 

از آنجا که این ممکن است کمی گیج کننده باشد ، در اینجا یک مثال است. یک فراخوان به greet_many() به پایین greetings.py اضافه کنید:

# greetings.py
...
greet_many(['Chad', 'Dan', 1])

 

این باید منجر به چاپ سلام برای هر سه نفر شود. با این حال، اگر این کد را اجرا کنید، نمونه ای از خروجی های چندگانه را مشاهده می کنید:

$ python greetings.py
Hello, Chad
Hello, Dan
Traceback (most recent call last):
  File "greetings.py", line 10, in greet_many
    greet(person)
  File "greetings.py", line 5, in greet
    print(greeting + ', ' + who_to_greet(someone))
TypeError: must be str, not int

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "greetings.py", line 14, in <module>
    greet_many(['Chad', 'Dan', 1])
  File "greetings.py", line 12, in greet_many
    print('hi, ' + person)
TypeError: must be str, not int

 

در وسط traceback بالا بخش During handling دقت کنید. در بین تمام tracebackها این خط را میبینید. پیغام آن کاملا مشخص است. زمانی که کد شما سعی داشت یک exception را کنترل کند، exception دیگری رخ داد.

 

استثناء اول را قبلاً مشاهده کرده اید، هنگامی که greet() را با یک عدد صحیح صدا زدید. از آنجا که ما عدد 1 را به لیست افرادی که باید سلام کنیم اضافه کردیم، می توانیم همان نتیجه را انتظار داشته باشیم. با این حال، تابع greet_many() فراخوان greet() را در یک try و except می پیچاند. در صورتی که greet() منجر به ایجاد استثناء شود، greet_many() می خواهد یک جمله پیش فرض را چاپ کند.

 

قسمت مربوطه greetings.py در اینجا تکرار می شود:

def greet_many(people):
    for person in people:
        try:
            greet(person)
        except Exception:
            print('hi, ' + person)

 

بنابراین وقتی greet() به دلیل ورودی صحیح نامناسب به TypeError منجر می شود، greet_many() این استثنا را مدیریت می کند و سعی می کند یک سلام ساده چاپ کند. در اینجا کد به پایان می رسد و منجر به یک استثنا دیگر می شود. هنوز در تلاش است یک رشته و یک عدد صحیح اضافه کند.

 

مشاهده همه خروجی های traceback می تواند به شما کمک کند ببینید علت واقعی یک استثنا چه چیزی می تواند باشد. گاهی اوقات وقتی می بینید که استثنای نهایی ایجاد شده، و با traceback مجدد ناشی از آن، هنوز نمی توانید اشکال را ببینید. در این موارد، حرکت به سمت استثنائات قبلی معمولاً تصور بهتری از علت اصلی به شما می دهد.

 

مقاله پیشنهادی: 11 کتابخانه پایتونی که هر برنامه نویسی باید بداند

 

# چند Traceback متداول پایتون

دانستن نحوه خواندن یک traceback پایتون در هنگام استثناء می تواند در هنگام برنامه نویسی بسیار مفید باشد، اما دانستن برخی از رایج ترین tracebackها نیز می تواند روند شما را تسریع کند.

 

در اینجا برخی از استثنائات رایج که ممکن است با آنها برخورد کنید، دلایل ایجاد آنها، منظور آنها، و اطلاعاتی که می توانید در traceback آنها پیدا کنید، ذکر شده است.

 

 

+ AttributeError

AttributeError هنگامی ایجاد می شود که می خواهید به یک ویژگی در یک شیء که آن ویژگی را مشخص نکرده دسترسی پیدا کنید. اسناد پایتون زمان افزایش این استثنا را مشخص می کند:

  • هنگامی که اشاره یا تخصیص ویژگی شکست بخورد، ایجاد میشود. (منبع)

 

در اینجا یک نمونه از AttributeError مطرح می شود:

>>> an_int = 1
>>> an_int.an_attribute
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'int' object has no attribute 'an_attribute'

 

خط پیام خطا برای AttributeError به شما می گوید که نوع شیء خاص، int در این مورد، به ویژگی دسترسی ندارد، an_attribute در این مورد. مشاهده AttributeError در خط پیام خطا می تواند به شما کمک کند تا به سرعت مشخص کنید که برای دسترسی به کدام ویژگی تلاش کرده اید و برای رفع آن به کجا مراجعه کنید.

 

بیشتر اوقات ، گرفتن این استثنا نشان می دهد که احتمالاً با شیئی کار می کنید که از نوع مورد انتظار شما نیست:

>>> a_list = (1, 2)
>>> a_list.append(3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'tuple' object has no attribute 'append'

 

در مثال بالا ، ممکن است انتظار داشته باشید که a_list از نوع list باشد که متدی به نام .append () دارد. هنگامی که استثنا AttributeError را دریافت می کنید و می بینید که هنگام تلاش برای فراخوانی (.append) به شما می گوید که احتمالاً با نوع شیئی که انتظار داشتید سر و کار ندارید.

 

اغلب، این زمانی اتفاق می افتد که شما انتظار دارید یک شیء از یک تابع یا فراخوانی متد از نوع خاصی برگردانده شود و در نهایت با یک شیء از نوع None مواجه می شوید. در این حالت، خط پیام خطا، AttributeError: 'NoneType' object has no attribute 'append' است.

 

 

+ ImportError

ImportError وقتی پیش می آید که با دستور import مشکلی داشته باشد. اگر ماژول موردنظر برای وارد کردن پیدا نشود یا اگر بخواهید چیزی را از ماژولی که در ماژول وجود ندارد وارد کنید، این استثنا یا زیر کلاس ModuleNotFoundError را دریافت خواهید کرد. اسناد پایتون زمان افزایش این استثنا را مشخص می کند:

  • هنگامی که دستور وارد کردن هنگام بارگیری یک ماژول با مشکل مواجه می شود، اجرا میشود. همچنین زمانی مطرح می شود که "from list" در from ... import نامی دارد که نمیتواند پیدا کند. (منبع)

 

در اینجا یک نمونه از ImportError و ModuleNotFoundError مطرح می شود:

>>> import asdf
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'asdf'
>>> from collections import asdf
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: cannot import name 'asdf'

 

در مثال بالا ، می بینید که تلاش برای وارد کردن ماژولی که وجود ندارد، asdf، منجر به ModuleNotFoundError می شود. هنگام تلاش برای وارد کردن چیزی که وجود ندارد، asdf، از یک ماژول موجود، مجموعه ها، این منجر به یک ImportError می شود. خطوط پیام خطا در پایین traceback به شما می گوید کدام مورد را نمی توان وارد کرد، asdf در هر دو مورد.

 

مقاله پیشنهادی: چرا از rabbitmq استفاده کنیم؟

 

+ IndexError

IndexError هنگامی ایجاد می شود که می خواهید یک آیتم را از یک دنباله، مانند یک لیست یا tuple، بازیابی کنید، و ایندکس در دنباله یافت نمی شود. اسناد پایتون زمان افزایش این استثنا را مشخص می کند:

  • زمانی اجرا میشود که زیرمجموعه دنباله ای خارج از محدوده باشد. (منبع)

 

در اینجا مثالی وجود دارد که IndexError را اجرا میکند:

>>> a_list = ['a', 'b']
>>> a_list[3]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range

 

خط پیام خطا برای IndexError اطلاعات خوبی به شما نمی دهد. می توانید ببینید که یک دنباله ای دارید که out of range است و نوع دنباله چیست، لیستی در این مورد. این اطلاعات، همراه با بقیه موارد traceback، معمولاً به اندازه کافی برای کمک به شما در تشخیص سریع مشکل است.

 

 

+ KeyError

KeyError هنگام تلاش برای دسترسی به کلیدی که در دنباله نیست، معمولاً دیکشنری، اجرا می شود. این را به عنوان IndexError در نظر بگیرید، اما برای دیکشنری ها. اسناد پایتون زمان افزایش این استثنا را مشخص می کند:

  • زمانی ایجاد مشود که کلید (دیکشنری) در مجموعه کلیدهای موجود یافت نشود. (منبع)

 

در اینجا نمونه ای از مطرح شدن KeyError آورده شده است:

>>> a_dict['b']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'b'

 

خط پیام خطا برای KeyError کلیدی را که پیدا نشد به شما می دهد. این مورد چندان ادامه پیدا نمی کند، اما در ترکیب با بقیه موارد traceback، معمولاً برای رفع مشکل کافی است.

 

 

+ NameError

NameError هنگامی مطرح می شود که شما متغیر، ماژول، کلاس، فانکشن یا نام دیگری که در کد شما تعریف نشده است فراخوانی میکنید. اسناد پایتون زمان اجرا این استثنا را مشخص می کند:

  • زمانی اجرا میشود که نام local یا global پیدا نشود. (منبع)

 

در کد زیر ، ()greet یک پارامتر person را می گیرد. اما در خود تابع، آن پارامتر به اشتباه persn نوشته شده است:

>>> def greet(person):
...     print(f'Hello, {persn}')
>>> greet('World')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in greet
NameError: name 'persn' is not defined

 

خط پیام خطای NameError نامی را که گم شده است به شما می دهد. در مثال بالا، این یک متغیر یا پارامتر غلط املایی برای عملکردی است که وارد شده است.

 

برای پارامتری که نادرست آن را نوشته اید، NameError نیز ظاهر می شود:

>>> def greet(persn):
...     print(f'Hello, {person}')
>>> greet('World')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in greet
NameError: name 'person' is not defined

 

در اینجا، ممکن است به نظر برسد که شما هیچ اشتباهی نکرده اید. آخرین سطری که در traceback اجرا و به آن اشاره شد خوب به نظر می رسد. اگر در چنین شرایطی قرار گرفتید، کاری که باید انجام دهید این است که از طریق کد خود به دنبال مکان استفاده و تعریف متغیر person باشید. در اینجا می توانید به سرعت مشاهده کنید که نام پارامتر اشتباه نوشته شده است.

 

مقاله پیشنهادی: GIL پایتون چیست؟

 

+ SyntaxError

هنگامی که نحو نادرست پایتون را در کد خود داشته باشید، SyntaxError مطرح می شود. اسناد پایتون زمان اجرای این استثنا را مشخص می کند:

  • هنگامی که مفسر پایتون با خطای نحوی مواجه می شود، اجرا میشود. (منبع)

 

در زیر ، مشکل یک دونقطه گم شده است که باید در انتهای خط تعریف تابع باشد. در Python REPL، این خطای نحوی بلافاصله پس از زدن enter وارد می شود:

>>> def greet(person)
  File "<stdin>", line 1
    def greet(person)
                    ^
SyntaxError: invalid syntax

 

خط پیام خطای SyntaxError فقط به شما می گوید که در نحو کد شما مشکلی وجود داشته است. نگاه کردن به خطوط بالا خطی را با مشکل نشان می دهد و معمولاً ^ (caret) نقطه مشکل را نشان می دهد. در اینجا ، کولون در دستور def تابع وجود ندارد.

 

همچنین، در  SyntaxError ، خط Traceback (most recent call last): وجود ندارد. این به این دلیل است که SyntaxError هنگامی ایجاد می شود که پایتون سعی می کند کد شما را تجزیه کند و خطوط در واقع اجرا نمی شوند.

 

 

+ TypeError

TypeError هنگامی مطرح می شود که کد شما سعی می کند کاری را با یک آبجکت انجام دهد که نمی تواند آن کار را انجام دهد، مانند تلاش برای اضافه کردن یک رشته به یک عدد صحیح یا فراخوانی len() در یک آبجکت که طول آن مشخص نشده است. اسناد پایتون زمان اجرا این استثنا را مشخص می کند:

  • هنگامی که یک عملیات یا عملکرد روی یک شیء از نوع نامناسب اعمال می شود ، اجرا میشود. (منبع)

 

در زیر چندین نمونه از TypeError مطرح شده است:

>>> 1 + '1'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'str'

>>> '1' + 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: must be str, not int

>>> len(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: object of type 'int' has no len()

 

همه مثالهای بالا برای ایجاد TypeError منجر به خط خطای پیام های مختلف می شود. هر یک از آنها کار خوبی را انجام می دهند تا شما را از اشتباهات خود آگاه کنند.

 

 

+ ValueError

ValueError زمانی مطرح می شود که مقدار شیء صحیح نباشد. شما می توانید این را به عنوان یک IndexError در نظر بگیرید که اجرا میشود زیرا مقدار index در محدوده دنباله نیست، فقط ValueError برای یک مورد عمومی تر است. اسناد پایتون زمان افزایش این استثنا را مشخص می کند:

  • زمانی مطرح می شود که یک عملیات یا تابع آرگومانی دریافت کند که دارای نوع مناسب اما مقدار نامناسب است و وضعیت با یک استثنا دقیق تر مانند IndexError توصیف نمی شود. (منبع)

 

در اینجا دو نمونه از ValueError مطرح شده است:

>>> a, b, c = [1, 2]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: not enough values to unpack (expected 3, got 2)

>>> a, b = [1, 2, 3]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 2)

 

مقاله پیشنهادی: چطور اسکریپت های پایتون را اجرا کنیم؟

 

# لاگ گیری Traceback

برخورد با یک استثنا و traceback پایتون به این معناست که باید تصمیم بگیرید که در مورد آن چه کاری انجام دهید. معمولا تعمیر کد شما اولین قدم است، اما گاهی اوقات مشکل از ورودی غیر منتظره یا نادرست است. در حالی که ارائه چنین شرایطی در کد شما خوب است ، گاهی اوقات منطقی است که با ورود به سیستم ردیابی و انجام کار دیگری، استثنا را خاموش یا پنهان کنید.

 

در اینجا یک مثال واقعی از کد وجود دارد که باید برخی از tracebackهای پایتون را خاموش کند. در این مثال از کتابخانه requests استفاده می شود.

# urlcaller.py
import sys
import requests

response = requests.get(sys.argv[1])

print(response.status_code, response.content)

 

این کد به خوبی کار می کند. هنگامی که این اسکریپت را اجرا می کنید ، URL را به عنوان آرگومان خط فرمان به آن می دهید، URL را فراخوانی می کند و سپس کد وضعیت HTTP و محتوا را از پاسخ چاپ می کند. حتی اگر پاسخ وضعیت خطای HTTP باشد کار می کند:

$ python urlcaller.py https://httpbin.org/status/200
200 b''
$ python urlcaller.py https://httpbin.org/status/500
500 b''

 

با این حال ، گاهی اوقات نشانی اینترنتی که اسکریپت شما برای بازیابی به آن داده شده وجود ندارد، یا سرور میزبان خراب است. در این موارد، این اسکریپت اکنون یک استثناء ConnectionError را ایجاد می کند و یک traceback را چاپ می کند:

$ python urlcaller.py http://thisurlprobablydoesntexist.com
...
During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "urlcaller.py", line 5, in <module>
    response = requests.get(sys.argv[1])
  File "/path/to/requests/api.py", line 75, in get
    return request('get', url, params=params, **kwargs)
  File "/path/to/requests/api.py", line 60, in request
    return session.request(method=method, url=url, **kwargs)
  File "/path/to/requests/sessions.py", line 533, in request
    resp = self.send(prep, **send_kwargs)
  File "/path/to/requests/sessions.py", line 646, in send
    r = adapter.send(request, **kwargs)
  File "/path/to/requests/adapters.py", line 516, in send
    raise ConnectionError(e, request=request)
requests.exceptions.ConnectionError: HTTPConnectionPool(host='thisurlprobablydoesntexist.com', port=80): Max retries exceeded with url: / (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7faf9d671860>: Failed to establish a new connection: [Errno -2] Name or service not known',))

 

traceback پایتون در اینجا می تواند بسیار طولانی باشد و بسیاری از استثنائات دیگر مطرح می شوند و در نهایت منجر به افزایش ConnectionError توسط خود requests می شود. اگر آخرین موارد استثناء را ردیابی کنید، می بینید که مشکل در کد ما با خط 5 urlcaller.py شروع شده است.

 

اگر خط متخلف را به صورت بلوک try-except بپیچید، گرفتن استثنا مناسب به اسکریپت شما اجازه می دهد تا با ورودی های بیشتر به کار خود ادامه دهد:

# urlcaller.py
...
try:
    response = requests.get(sys.argv[1])
except requests.exceptions.ConnectionError:
    print(-1, 'Connection Error')
else:
    print(response.status_code, response.content)

 

کد بالا از یک عبارت else با بلوک try-except استفاده می کند.

 

حالا وقتی اسکریپت را با URL اجرا می کنید که منجر به بالا آمدن خطای ConnectionError می شود، یک -1 برای کد وضعیت و خطای اتصال محتوا چاپ می کنید:

$ python urlcaller.py http://thisurlprobablydoesntexist.com
-1 Connection Error

 

این عالی کار می کند. با این حال، در اکثر سیستم های واقعی، شما نمی خواهید فقط استثنا و traceback را خاموش کنید، بلکه می خواهید traceback را ثبت کنید. Logging به شما امکان می دهد درک بهتری از اشتباهات برنامه های خود داشته باشید.

 

ویدیو پیشنهادی: ویدیو آموزش ماژول logging در پایتون

 

شما میتوانید با ماژول logging پایتون مشکلاتی که در زمان اجرای کد اتفاق میفتند را ثبت کنید. اسکریپت نهایی شما باید چیزی شبیه کد زیر باشد:

# urlcaller.py
import logging
import sys
import requests

logger = logging.getLogger(__name__)

try:
    response = requests.get(sys.argv[1])
except requests.exceptions.ConnectionError as e:
    logger.exception()
    print(-1, 'Connection Error')
else:
    print(response.status_code, response.content)

 

حالا وقتی اسکریپت را برای آدرس اینترنتی مشکل ساز اجرا می کنید ، -1 مورد انتظار و خطای اتصال را چاپ می کند، اما همچنین traceback را log می کند:

$ python urlcaller.py http://thisurlprobablydoesntexist.com
...
  File "/path/to/requests/adapters.py", line 516, in send
    raise ConnectionError(e, request=request)
requests.exceptions.ConnectionError: HTTPConnectionPool(host='thisurlprobablydoesntexist.com', port=80): Max retries exceeded with url: / (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7faf9d671860>: Failed to establish a new connection: [Errno -2] Name or service not known',))
-1 Connection Error

 

به طور پیش فرض ، پایتون پیام های گزارش را به خطای استاندارد (stderr) ارسال می کند. به نظر می رسد که ما اصلا خروجی traceback را مخفی نکرده ایم. با این حال، اگر هنگام تغییر مسیر stderr دوباره آن را صدا کنید، می بینید که سیستم logging کار می کند، و ما می توانیم گزارش های خود را بعداً ذخیره کنیم:

$ python urlcaller.py http://thisurlprobablydoesntexist.com 2> my-logs.log
-1 Connection Error

 

 

# نتیجه گیری

traceback پایتون حاوی اطلاعات بسیار خوبی است که می تواند به شما کمک کند اشتباهات کد پایتون را پیدا کنید. این tracebackها می توانند کمی ترسناک به نظر برسند، اما وقتی آنها را تجزیه کردید تا ببینید آنچه می خواهد به شما نشان دهد، می توانند بسیار مفید باشند. مرور چند خط  tracebacksدرک بهتری از اطلاعات موجود در آنها به شما می دهد و به شما کمک می کند از آنها بیشترین بهره را ببرید.

 

مطالب مشابه



مونگارد