Профилиране и отстраняване на грешки Python, отстраняване на грешки
В предишната статия приключихме нашата дискусия относно профилирането с общ преглед на програмистите за профилиране на събития.
Днес предлагам да разгледаме методите за отстраняване на грешки в програми.
- Въведение и теория – защо изобщо е необходимо профилирането, различни подходи, инструменти и разлики между тях
- Ръчно и статистическо профилиране - преминаване към практиката
- Профилиране на събития – инструменти и тяхното приложение
- Отстраняване на грешки - какво да правите, когато нищо не работи
Преди да започнем да говорим за отстраняване на грешки, трябва да решим какво е то. По традиция нека се обърнем към Уикипедия: „Отстраняване на грешки - откриване, локализиране и премахване на грешки“. Като цяло, за успешно отстраняване на грешки в програмата, имаме нужда (но не винаги достатъчно) две неща: стойността на променливите на мястото на програмата, където е възникнала грешката, както и проследяването на стека: редът на извикване на функции, до грешната. Също така е полезно да знаете за средата, в която работи програмата: наличието (или липсата) на свободна памет, системните ограничения (например за броя на файловите дескриптори) и т.н., но това е малко извън обхвата на нашата статия.
Класика на жанра
Какво прави един начинаещ програмист, когато иска да "проникне" в програмата и да проучи съдържанието на променливите (на правилните места) и логиката на програмата (извиквания на функции, условия)? Той прибягва до най-често срещания, най-простият и най-мощният метод за отстраняване на грешки: поставяне на „отпечатъци“ в целия код (изявлението за печат в Python 2.x и функцията print() в Python 3.x). Но не само начинаещите грешат с това: напредналите разработчици често са твърде мързеливи, за да използват специални инструменти за отстраняване на грешки, надявайки се бързо, след няколко минути, да намерят причината за грешката и да поправят всичко, без да забелязват, че търсенето на грешкиразпределени в часове и дори дни. Между другото, този подход се нарича "дневник".
Това също включва запис на цялата информация, необходима за отстраняване на грешки в програмата, в лог файл. Понякога няма други опции, например, когато скриптът работи в производство и грешки се появяват спорадично или когато грешката се появява само след като програмата е работила дълго време (да речем, две или три седмици след стартирането).
Но ние пишем на Python, така че защо да не се възползваме от вградените инструменти за отстраняване на грешки или инструментите, предлагани от общността? Например, вместо обичайното регистриране във файл, има смисъл да използвате Sentry, така че в допълнение към съобщението за грешка можете да изпратите допълнителна информация: проследяване на стека с всички локални променливи, всякакви други променливи и като цяло всичко, което сметнете за добре.
Дебъгерът на Python
Python има вграден дебъгер: модулът pdb. По принцип това може да е краят на статията, т.к. pdb е изключително мощен дебъгер и всичко останало всъщност е само "украса" към него. Но ще продължим =)
Както можете да видите от името, pdb взе много от gdb (GNU Project debugger) - дебъгер за C (и не само) програми. Между другото, програмите на Python също могат да бъдат дебъгвани с помощта на gdb, просто е малко по-сложно и по-дълго, въпреки че тези, които искат да се задълбочат в структурата на езика, както и тези, които пишат sish модули за python, не могат без gdb. В допълнение, gdb ви позволява да се свържете с вече работеща програма (чрез нейния pid) и да я дебъгвате „право на място“.
IPython pdb
Предлагам незабавно да инсталирате IPython и ipdb модула за него:
IPython (и ipdb, като част от него) предлага "по-добра" конзола и в резултат на това по-удобно отстраняване на грешки на програми: осветяване на код, автоматично довършване, история на командите, динамичниинтроспекция на всякакви обекти, магически функции, псевдоними и много други. За пълен списък с подобрения вижте документацията или директно от конзолата на IPython, като напишете "?" като екип. Всичко това помага при отстраняването на грешки и го прави лесно и забавно.
Можете да започнете отстраняване на грешки в скрипт в ipdb по няколко начина:
Тези команди ще отворят програмата в дебъгера, след което можете да правите каквото искате: да зададете точки на прекъсване, да изучавате работата й стъпка по стъпка или просто да стартирате програмата - дебъгерът автоматично ще спре, когато възникне неуловено изключение.
Но обикновено тази опция е твърде изтощителна: докато стигнете до правилното място с всички тези „следваща“, „стъпка“ и задаването на точка на прекъсване („прекъсване“) с ръцете ви всеки път е уморително. Много по-удобно е да вмъкнете следния ред на правилното място в програмата:
И тогава, когато този ред се изпълни, изпълнението на програмата ще спре и дебъгерът ще бъде стартиран - тогава можете да започнете да се задълбочавате в изучаването на програмата. Всъщност функцията "set_trace" е настройката на точка на прекъсване (точка на прекъсване).
Python Debugger има друг режим на работа, който в някои случаи е по-удобен от функцията set_trace. Нарича се "post mortem": стартиране на дебъгера с дадена обратна връзка:
Ако във функцията "some_code" възникнат неуловими изключения, дебъгерът ще бъде извикан в точката в програмата, където е възникнало изключението.
Интересен заместител на функцията "set_trace" е модулът за отстраняване на грешки, който просто импортира ipdb и виж библиотеките (удобна алтернатива на функцията dir) и започва отстраняване на грешки. Единственото предимство на модула е лекотата на използване, достатъчно е да вмъкнете реда навсякъде в програмата:
И когато този ред се изпълни, дебъгерът "ipdb" ще бъде извикан и модулът "see" ще бъде импортиран.
ipdbplugin
Още една интересна и този път полезна библиотека: nose-ipdb. С него можете автоматично да стартирате дебъгера при грешки (изключения) или просто при неправилно изпълнени тестове (надявам се, че използвате nos? =). За да стартирате ipdb дебъгера при грешки, е достатъчно да добавите ключа "--ipdb", когато изпълнявате тестовете:
И за да стартирате дебъгера в случай на неправилно завършени тестове, трябва да добавите ключа "--ipdb-failures":
Разбира се, можете да хванете всичко наведнъж:
Използвам този модул всеки ден и просто не мога да си представя живота си без него.
Друг добър модул, този път за Django: django-pdb. Позволява ви да стартирате дебъгера, ако има съответен GET параметър в заявката (например: http://127.0.0.1:8000/app/view?ipdb) или за всички заявки:
Или извикайте програмата за отстраняване на грешки, когато възникнат изключения (режим „post mortem“):
django-разширения
Но е много по-добре в Django да използвате модула django-extensions, който добавя много полезна команда runserver_plus. С тази батерия можете да се сприятелите с Django и Werkzeug (вижте по-горе) и да започнете да се наслаждавате на страници с петстотин грешки =)
За да използвате цялото това чудо, достатъчно е да стартирате сървъра за разработка с помощта на командата runserver_plus:
Отстраняването на грешки в програма в среда за разработка, разбира се, е удобно и добро, но най-трудното е да локализирате проблема, като използвате доклад за грешка от жив потребител. Понякога е трудно. Въпреки всички предимства на Python, модулът „телепатия“ не съществува и разработчикът остава сам с думите на потребителя „нищо не работи. единадесет".
Проектът Sentry ви позволява да съхраняватевсяка потребителска грешка с текста на изключението, пълната следа на стека на изключението и стойностите на всичкилокални променливи във всяка от функциите за проследяване на стека, както и много друга информация: среда на потребителя (браузър, операционна система), всички заглавки на заявки и като цяло всичко, което желае разработчикът.
Идентични бъгове са групирани заедно, така че можете да видите "пулса" на проекта и първо да коригирате най-критичните проблеми. Друг пример за използване на караул е регистриране. Можете просто да добавите запис в регистъра на съобщенията с всякакви променливи, които представляват интерес за разработчика, на спорното място и всичко това ще се окаже на стража.Но най-големият плюс е, че всичко това може (и трябва!) да се използва в производството.
Друг интересен дебъгер: PuDB е конзолен дебъгер с графичен интерфейс:
Няма да пиша много за него (честно казано, аз самият не съм го използвал активно), предлагам да прочетете кратка бележка на Habré: Удобен дебъгер за Python/Django проекти от потребител int22h или по-пълен преглед: Отстраняване на грешки в Python/Django с PuDB.Самостоятелен дебъгер на Python, този път с пълен GUI: Winpdb:
Разработчиците му твърдят, че winpdb е 20 пъти по-бърз от pdb и също така поддържа нишки. Много голям и подробен урок може да бъде намерен на тази страница: code.google.com/p/winpdb/wiki/DebuggingTutorial.