Вы пишете операторы print() для отладки кода Python?
Я был одним из тех, кто отлаживал код с помощью операторов print(). Иногда, если код длинный, то приходится выводить больше символов, чтобы отличить один от другого.
Посмотрите на фрагмент кода ниже.
(Фрагменты кода в этом блоге соответствуют синтаксису Python 3.7)
print(style_dict,"{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{}}}}}}}}}}}}}}}}}}}}}}}}}}]]]]]]]]]]]]]]]]]]]") # Adding into a dictionary res_dct = {style_dict[i]: style_dict[i + 1] for i in range(0, len(style_dict), 2)} res_dist={res_dct['Email Address']:{style_dict[i]: style_dict[i + 1] for i in range(0, len(style_dict), 2)}} print(res_dist,"+++++++++++++++++++++++++++++++++++++++++++++++++++++") recon_dict = res_dct print(recon_dict,"---------------------------------------------------") # Removing space so that data can be transferred to HTML fields recon_dict = {x.translate({32: None}): y for x, y in list(recon_dict.items())} print("##################################################") print(recon_dict) print("################################################") # Converting to JSON r = json.dumps(recon_dict) print("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$") print(r) loaded_json = json.loads(r) print("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWwwwwww") print("******************************************************") print(loaded_json)
Здесь я пытаюсь добавить словарь в файл JSON. Из-за некоторой ошибки мне пришлось использовать такое количество операторов print с различными символами для отладки.
Но когда код становится больше с различными модулями и различными классами, вызывающими различные определения в других модулях или классах, это не является правильным выбором.
Давайте посмотрим на некоторые недостатки этого подхода:
- При увеличении количества добавляемого кода трудно использовать операторы печати в каждом модуле, классе или определении, через которые проходит код.
- Еще до того, как мы заметили ошибку, код выполняется и переходит к следующим шагам.
- Ожидание завершения длительного выполнения, чтобы найти и исправить ошибку.
- Возвращение к целой куче журналов для поиска нужных символов, которые мы дали в операторах печати, и их сопоставление - утомительно.
Нам казалось, что выдача отпечатков - это простое решение для отладки, но не кажется ли это теперь утомительным.
Простой оборот
Нам не нужно ничего делать, кроме как использовать мощное оружие, которое предоставляет нам Python, - "модуль pdb". Этот модуль помогает нам эффективно отлаживать.
Что такое pdb (python debugger)?
pdb - это интерактивная оболочка, которая помогает отлаживать код python. Она помогает нам входить в наш код по одной строке за раз, делать паузу, исследовать состояние и переходить к следующей строке кода или продолжать выполнение.
Некоторые способы вызова pdb:
Здесь мы рассматриваем 3 способа вызова pdb.
Postmortem: Используйте это, если вы хотите отлаживать на уровне программы.
Inline pdb: Используйте это, если вы работаете с версиями, более ранними, чем 3.7
breakpoint(): Используйте это, для версии 3.7 и выше
Postmortem
Давайте разберемся с помощью простой программы.
debug_add.py
def add_num(listA,num): sum=[] for i in listA: sum.append(i*num) return sum listA = [2, 4, 6, 8] num=10 result=add_num(listA,num) print(result)
Здесь def add_num должен добавить значение переменной num к каждому элементу списка listA, сохранить новые значения в списке sum и вернуть сумму списка.
Выполнение файла python, как показано ниже, вызовет pdb,
python -m pdb debug_add.py
Это приведет к переходу в режим pdb и остановке на первой строке кода.
(venv) C:\Users\PycharmProjects\>python -m pdb debug_add.py > c:\users\pycharmprojects\debug_add.py(2)<module>() -> def add_num(listA,num): (Pdb)
В любое время, если вам нужна помощь в работе с отладчиком, используйте 'h'(help), где перечислены все опции.
(Pdb) hDocumented commands (type help <topic>): ======================================== EOF c d h list q rv undisplay a cl debug help ll quit s unt alias clear disable ignore longlist r source until args commands display interact n restart step up b condition down j next return tbreak w break cont enable jump p retval u whatis bt continue exit l pp run unalias whereMiscellaneous help topics: ========================== exec pdb
Справка по определенной опции,
(Pdb) h debug debug code Enter a recursive debugger that steps through the code argument (which is an arbitrary expression or statement to be executed in the current environment).
Вернитесь к программе, для перехода к следующему шагу выполнения используйте опцию 'n'(next).
> c:\users\pycharmprojects\debug_add.py(2)<module>() -> def add_num(listA,num): (Pdb) n > c:\users\prade\pycharmprojects\jobportal\debug_add.py(8)<module>() -> listA = [2, 4, 6, 8]
Здесь мы можем исследовать значения переменной, задав ее имя, как показано ниже,
(Pdb) listA *** NameError: name 'listA' is not defined (Pdb) *** NameError: name 'listA' is not defined
Мы дошли до строки listA = [2, 4, 6, 8], но все еще не выполнили, поэтому написано listA not defined. Если вы заметили, что если мы нажмем Enter в любое время, то предыдущий вариант будет выполнен, как описано выше.
Теперь нажмите 'n', чтобы двигаться вперед и проверить переменную listA.
(Pdb) n > c:\users\pycharmprojects\debug_add.py(9)<module>() -> num=10 (Pdb) listA [2, 4, 6, 8] (Pdb)
Чтобы проверить, в какой строке кода мы находимся, используйте опцию 'l' (line). Стрелка указывает на строку, в которой мы находимся, EOF означает конец файла.
(Pdb) l 4 for i in listA: 5 sum.append(i*num) 6 return sum 7 8 listA = [2, 4, 6, 8] 9 -> num=10 10 result=add_num(listA,num) 11 print(result) [EOF] (Pdb)
Для выхода из отладчика мы используем опцию 'q' (quit).
(Pdb) q(venv) C:\Users\PycharmProjects\>
Другой способ использовать метод postmortem - остановить выполнение, только когда встречается исключение, Для этого используйте -c continue вместе с -m pdb.
python -m pdb -c continue debug_add.py
Inline pdb
В ранних версиях Python 3.7 мы должны явно импортировать модуль pdb и вызвать pdb.set_trace(), чтобы остановить программу и выполнить отладку.
def add_num(listA,num): sum=[] for i in listA: sum.append(i*num) return sum listA = [2, 4, 6, 8] num=10 import pdb; pdb.set_trace() result=add_num(listA,num) print(result)
Давайте рассмотрим консоль, когда мы запускаем это.
> c:\users\pycharmprojects\debug_add.py(11)<module>() -> result=add_num(listA,num) (Pdb)
breakpoint()
Начиная с Python 3.7, появилось определение breakpoint(), которое помогает отлаживать питонический код без необходимости явного импорта модуля pdb и вызова pdb.set_trace(). breakpoint() делает все это за нас и открывает отладчик PDB в консоли.
Теперь давайте выполним приведенный выше код без точек останова и отладим, если возникнут ошибки.
def add_num(listA,num): sum=[] for i in listA: sum.append(i*num) return sum listA = [2, 4, 6, 8] num=10 result=add_num(listA,num) print(result)
Выход:
C:\Users\PycharmProjects\venv\Scripts\python.exe C:/Users/PycharmProjects/debug_add.py [20, 40, 60, 80]Process finished with exit code 0
Задача блока кода состоит в том, чтобы добавить число, равное 10, к каждому из элементов списка и вернуть новый список.
Ожидаемый результат - [12, 14, 16, 18]
Фактический результат - [20, 40, 60, 80]
Теперь давайте воспользуемся инструментом breakpoint() для отладки и исправления кода.
Место установки точки останова() зависит от того, где вы подозреваете наличие ошибки. В данном случае мы помещаем его перед входом в определение add_num().
def add_num(listA,num): sum=[] for i in listA: sum.append(i*num) return sum listA = [2, 4, 6, 8] num=10 breakpoint() result=add_num(listA,num) print(result)
Выход:
> c:\users\pycharmprojects\debug_add.py(11)<module>() -> result=add_num(listA,num) (Pdb) n > c:\users\pycharmprojects\debug_add.py(12)<module>() -> print(result) (Pdb) n [20, 40, 60, 80] — Return — > c:\users\prade\pycharmprojects\jobportal\debug_add.py(12)<module>()->None -> print(result) (Pdb)
Опция 'n'(next) используется для перехода к следующей строке или перешагивания через любые определения. Но в данном случае нам нужно перейти к определению, для этого мы используем опцию 's'(step).
Ниже текст, выделенный жирным шрифтом, используется для выделения используемой опции и ее объяснения.
> c:\users\prade\pycharmprojects\jobportal\debug_add.py(11)<module>() -> result=add_num(listA,num) (Pdb) s <----- Step into def add_num --Call-- > c:\users\prade\pycharmprojects\jobportal\debug_add.py(2)add_num() -> def add_num(listA,num): (Pdb) s <---- stepped inside def add_num > c:\users\prade\pycharmprojects\jobportal\debug_add.py(3)add_num() -> sum=[] (Pdb) n <--- inside a def feel free to use 'n' > c:\users\prade\pycharmprojects\jobportal\debug_add.py(4)add_num() -> for i in listA: (Pdb) n > c:\users\prade\pycharmprojects\jobportal\debug_add.py(5)add_num() -> sum.append(i*num) (Pdb) n > c:\users\prade\pycharmprojects\jobportal\debug_add.py(4)add_num() -> for i in listA: (Pdb) sum <-- examine sum value [20] <--- 2+10 =12 not 20,oops we used '*'instead of '+' in appending to list sum,CAUGHT IT! (Pdb) i <-- so, examine i 2 (Pdb) sum.append(i+num) <-- try adding + in the expression (Pdb) sum [20, 12] <-- PERFECT, FIXED IT! (Pdb) u <-- used to skip other iterations of for loop. > c:\users\prade\pycharmprojects\jobportal\debug_add.py(11)<module>() -> result=add_num(listA,num) (Pdb) c <-- used to continue with execution [20, 12, 40, 60, 80] <--not a right answer but found a fix.Process finished with exit code 0
Выше, после первой итерации цикла for, мы просмотрели значение суммы, и оно отобразило 20 вместо 12. Мы почти поймали себя на том, что ошибочно поставили *(умножение) вместо +(сложение). Тогда мы сделали шаг вперед и рассмотрели 'i', которое в этот момент равно 2, и попробовали sum.append(i+num). Затем рассмотрение суммы дало нам 12 как недавно добавленный элемент. Следовательно, мы получили исправление, поэтому пропустили оставшиеся итерации цикла for, используя опцию 'u' (until). Затем перешли к следующему шагу после цикла. Здесь мы использовали 'c' (continue), чтобы продолжить выполнение, и оно завершилось.
Теперь исправление,
def add_num(listA,num): sum=[] for i in listA: sum.append(i+num) return sum listA = [2, 4, 6, 8] num=10 result=add_num(listA,num) print(result)
Выход:
C:\Users\PycharmProjects\venv\Scripts\python.exe C:/Users/PycharmProjects/debug_add.py [12, 14, 16, 18]Process finished with exit code 0
Отлажено!!!
Разве это не кажется простым, без беспорядочных операторов print()?
Небольшой обзор опций pdb, используемых здесь:
n - перейти к следующей строке/перешагнуть через определения
s - перейти к определениям (встроенным / определенным пользователем)
u - пропустить оставшиеся итерации в цикле
c - продолжить выполнение или пока не будет найдена следующая точка останова() <
l - показать стрелкой "->"
текущую строку кода для выполнения q - выход из отладчика
имя переменной - посмотреть текущее состояние переменной
h имя опции - отображение справки по предоставленной опции
h - для просмотра меню опций и изучения дополнительных опций по мере необходимости.
Заключение
pdb - это мощное оружие для отладки Pythonic кода, которое добавляет "эффективность", поскольку в вашем коде нет беспорядочных операторов print()и "эффективность", поскольку значительно сокращает время отладки.
С кучей предоставленных опций, это должен быть ваш инструмент "goto", когда вы столкнетесь с вашей следующей ошибкой.
Вернуться на верх