Если вы скажете профессиональным программистам, что используете print()
для отслеживания ошибок, готовьтесь уворачиваться от летящих в вашу сторону стульев. Есть ли смысл продираться через дебри трассировки стека с полной настройкой отладки, будучи новичком? Некоторые скажут “да”, поскольку они изначально научились это делать. Я же утверждаю: “Любые средства хороши — был бы результат”.
Это совсем не значит, что вам не нужно учиться распознавать ошибки — речь о другом. Когда вы программируете в свое удовольствие или намереваетесь создать для кого-либо небольшие фрагменты кода, так ли необходимо проводить отладку на профессиональном уровне? Если вы занимаетесь программированием себе на радость и в свободное время, то вряд ли вам потребуется проводить “образцовую” отладку на протяжении всей вашей карьеры разработчика.
Print() — быть или не быть
В большинстве случаев коду рано или поздно потребуется отладка. К счастью, существует несколько способов ее осуществить, не прибегая к полному каноническому варианту разработчика.
Прежде всего посмотрим, как функция print()
может помочь в отладке кода.
print()
print()
обеспечит мгновенное визуальное воплощение того, над чем вы работаете. Если вы ожидаете вполне определенный результат, то сразу же увидите его в терминале. Если он верный — смело продолжайте работу. Если нет — ищите причину.
Рассмотрим пример с применением print()
:
greek_gods = ['Zeus','Poseidon','Apollo','Bob']
greek_gods_only = [god for god in greek_gods if god!='Bob']
gods = ','.join(greek_gods_only)
Как узнать, удалось ли изгнать Боба (Bob
) из стана богов?
print(gods)
А теперь, когда Боб вернулся с небес на землю, можно рассмотреть пример из реальной практики.
Не так давно я разработал инструмент в Autodesk Maya для управления камерами. В анимационной сцене мне потребовалось составить список всех камер съемки, исключив камеры, используемые в этом редакторе по умолчанию. К счастью для нас, в Maya они уже определены (startupCamera = True
), поэтому их легко найти.
import maya.cmds as cmds
list_cameras = cmds.listCameras()
cam_list = [cam for cam in list_cameras if not cmds.camera(cam, q=True, startupCamera=True)]
for cam in cam_list:
print(cam)
Как видите, первые три позиции в списке по-прежнему занимают ненужные камеры из каких-то ссылочных файлов. Теперь, воочию столкнувшись с этой ошибкой, я могу ее устранить, добавив and ‘face’ not in cam
:
Не примени я функцию print
для проверки вывода, пришлось бы пропускать код через конвейер. Вернулось бы сообщение об ошибке, и мы бы потратили время на ее обнаружение. А ошибка-то не очевидная, поскольку относится к разряду логических, а не тех, что останавливают выполнение кода.
Вывод данных с помощью print
бережет наши деньги!
Альтернативные варианты отладки
Итак, вы, несомненно, хотите узнать доступные вам альтернативы отладки. С удовольствием используя print
, вы понимаете, что неплохо бы расширить диапазон возможностей и пополнить “оружием” свой арсенал.
Рассмотрим ряд дополнительных способов отладки кода. Надеюсь, какой-нибудь из них придется вам по душе (или вы просто продолжите работать с print
).
Python Tutor
Python Tutor представляет собой простой и визуальный подход. Этот ресурс позволяет выполнять код и наглядно демонстрирует, что происходит на каждом его этапе.
Возьмем, к примеру, очень продвинутую функцию. Добавим код и кликнем на Visualize Execution (визуализация выполнения).
После этого вы сможете работать с кодом, переходя от одной строки к другой. Код находится с левой стороны, а вывод данных — справа.
В следующем примере показан заключительный этап программы (шаг 9). В строке 4 происходит выполнение sum_input(10,10)
, и справа мы видим функцию и значение, которое она возвращает.
Assert
“Assert — это просто логическое выражение, которое проверяет, возвращают ли условия true
или false
. Если значение верно, то программа никак не реагирует и переходит к следующей строке кода. Однако, если оно ложно, то программа останавливается и выбрасывает ошибку” [Источник programiz].
Перед вами простой пример использования assert
:
def sum_input(input_a, input_b):
return input_a + input_b
assert sum_input(2,3) == 5
assert sum_input(2,3) != 5
С помощью assert
можно проверить, соответствует ли выполнение кода ожиданиям. В вышеуказанном примере вы ждете возврата значения 5, поэтому используете этот код, который возвращает True
.
assert sum_input(2,3) == 5
А есть и такой код:
assert sum_input(2,3) != 5
2 + 3 в результате всегда дает только 5, следовательно вы ожидаете ошибку, которую и получаете. Измените код следующим образом assert sum_input(2,3) != 6
или укажите любое число кроме 5, и у вас не будет ошибок.
Поскольку именно вы инициируете эти ошибки, то их отсутствие было бы странным. Хотите почистить код — воспользуйтесь вот этим вариантом:
def sum_input(input_a, input_b):
return input_a + input_bassert sum_input(2,3) == 5
assert sum_input(2,3) != 6
Можете создать свои собственные сообщения об ошибках:
assert sum_input(2,3) != 5, '2+3 is 5...Stop this nonsense'
Thonny
Не так давно состоялось мое первое знакомство с Thonny, и она не оставила мне выбора — я влюбился. Это простая IDE со встроенным отладчиком, который показывает все, что происходит в коде. Среда на удивление простая, а возможности отладки превосходят все ожидания.
Рассмотрим следующий пример кода: программа проверяет все файлы, находящиеся в той же папке, что и программа Python. Затем она возвращает список с кортежем: (‘filename’, ‘extension’)
.
import os
import pathlib
def get_file_exts(directory):
#перечисляет все файлы в директории
search_path = pathlib.Path(directory).iterdir()
file_list = [file.name for file in search_path if file.is_file()]
#создает новый список с кортежем, включающем имена и расширения всех файлов:
file_ext = [os.path.splitext(file) for file in file_list]
return file_ext
def main():
#где находится файл:
current_dir = os.path.dirname(os.path.realpath(__file__))
#вызывает функцию для получения имен файлов и расширений, затем выводит данные.
for file in get_file_exts(current_dir):
print(file)
if __name__ == '__main__':
main()
Thonny проинформирует вас о том, всё ли в порядке с вашим кодом. Ниже мы видим выполнение этого кода и возвращаемые им результаты:
Если намеренно добавить ошибку, например переименовать search_path
в searchc_path
, то среагирует Помощник:
Помощник также снабжает нас подсказками, облегчая процесс поиска и устранения ошибок. Если мы развернем вопрос “Did you misspell it (somewhere)?”, в котором он интересуется, а правильно ли было написано имя, то Thonny покажет нам похожие варианты имен и станет очевидно, где была допущена ошибка.
Если вы запускаете режим отладки, то Thonny пошагово выполнит код и покажет все, что в нем происходит:
Он останавливается на строке 24 с инструкцией if
.
pdb — встроенный отладчик Python
Если же вы предпочитаете работать в терминале, то Python оснащен встроенным отладчиком, известным как pdb
. Благодаря ему вам не приходится повсюду в коде применять функции print()
. Помимо этого, вы можете проверять функции и переменные и тестировать код в реальном режиме без редактирования его исходного варианта. Используя данный способ отладки, вы не ломаете код только из-за необходимости протестировать те или иные случаи.
Просто добавив в код breakpoint()
, вы укажите интерпретатору, где именно вы намерены войти в режим отладки. Если у вас отсутствует новая версия Python (3.X), то придется внести дополнительную строку import pdb; pdb.set_trace()
.
Более подробную информацию о pdb
вы найдете в соответствующей документации.
Real Python также предоставляет полезный обучающий материал о возможностях отладчика.
Заключение
Функция print()
не заменит качественную отладку. Этот способ не приемлем для командной разработки, но вполне может подойти начинающим программистам. И почитателей print()
гораздо больше, чем мы думаем. Во-первых, она ускоряет процесс отладки; во-вторых, вы узнаёте, каким должен быть ожидаемый результат; в-третьих, она моментально предоставляет наглядную информацию.
Не сдерживайте себя в стремлении изучить альтернативные варианты отладки. Возможно, вы найдете какой-то новый способ, который подойдет именно вам.
Если же вы намерены и дальше использовать print()
— я только “за”. Главное, чтобы сеньоры были не против.
Читайте также:
- Импорт в Python
- Продвинутый Python: 9 важнейших аспектов при определении классов
- Python: как заменить циклы For на Map, Filter и Reduce
Читайте нас в Telegram, VK и Яндекс.Дзен
Перевод статьи Martin Andersson Aaberge: Ignore the Professionals — Debug Your Python Code Using Print()