Вы пишете операторы 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", когда вы столкнетесь с вашей следующей ошибкой.
Back to Top