Чистыйкод дляпродолжающи х
Скачать 7.85 Mb.
|
Глава 14. Проекты для тренировки. Я расскажу о нескольких полезных методах, а затем с их помощью мы напишем пару игр командной строки: головоломку с перемещением дисков «Ханойская башня» и классическую игру «Четыре в ряд» для двух игроков. Часть III. Объектно-ориентированный Python Глава 15. Объектно-ориентированное программирование и классы. Здесь мы определим роль объектно-ориентированного программирования (ООП), которое часто понимают неправильно. Многие разработчики злоупотребляют средствами ООП в своем коде, потому что считают, что так поступают все, но это лишь усложняет исходный код. Вы научитесь использовать классы, но что еще важнее, вы узнаете, когда следует и когда не следует их применять. Путешествие в мир программирования 23 Глава 16. Объектно-ориентированное программирование и наследование. Наследование классов и его полезность для повторного использования кода. Глава 17. ООП в Python: свойства и dunder-методы. Средства объектно- ориентированного проектирования, специфические для Python: свойства, dunder-методы и перегрузка операторов. Путешествие в мир программирования Попытки новичка стать профессиональным программистом часто выглядят чем-то вроде попытки напиться из пожарного шланга. При таком изобилии ресурсов вы начинаете беспокоиться, что тратите время на неэффективные учебники. После того как вы прочтете эту книгу (или даже во время чтения), я рекомендую ознакомиться со следующими вводными материалами. «Python Crash Course» (No Starch Press, 2019) Эрика Мэтиза (Eric Matthes) 1 — книга для начинающих, но благодаря ее ориентации на конкретные проекты даже опытный программист почувствует вкус использования библиотек Python Pygame, matplotlib и Django. В своей книге «Impractical Python Projects» (No Starch Press, 2018) Ли Воган (Lee Vaughan) 2 проектным методом совершенствует ваши навыки Python. Под его руководством вы построите несколько занимательных программ, которые станут для вас отличной тренировкой. «Serious Python» (No Starch Press, 2018) Джульена Данжу (Julien Danjou) 3 описывает, что надо предпринять любителю-энтузиасту для превращения в квалифицированного разработчика, который применяет передовые прак- тики и пишет хорошо масштабируемый код. Впрочем, технические аспекты Python — всего лишь одна из его сильных сторон. Язык программирования сформировал разностороннее сообщество, усилиями которого была создана удобная, доступная документация и система поддержки, превосходящая любую другую экосистему. На ежегодной конференции PyCon наряду со многими региональными конференциями предлагаются многочислен- ные лекции для программистов разных уровней квалификации. Организаторы 1 Мэтиз Э. Изучаем Python: программирование игр, визуализация данных, веб-прило жения. 3-е изд. — СПб.: Питер. 2 Воган Л. «Непрактичный» Python. Занимательные проекты для тех, кто хочет поумнеть. 3 Данжу Дж. Путь Python. Черный пояс по разработке, масштабированию, тестированию и развертыванию. — СПб.: Питер. 24 Введение PyCon предоставляют бесплатный доступ к этим материалам на https://pyvideo. org/. На странице Tags можно легко найти доклады по темам, интересующим вас. Если вы захотите глубже изучить расширенные возможности синтаксиса и стан- дартной библиотеки Python, я рекомендую следующие книги: «Effective Python» (Addison-Wesley Professional, 2019) Бретта Слаткина (Brett Slatkin) 1 — впечатляющая подборка передовых практик и языковых средств Python; «Python Cookbook» (O’Reilly Media, 2013) Дэвида Бизли (David Beazley) и Брайана К. Джонса (Brian K. Jones) 2 — обширный список фрагментов кода, которые помогут обновить репертуар любого начинающего разработчика Python; «Fluent Python» (O’Reilly Media, 2021) Лучано Рамальо (Luciano Ramalho) 3 — капитальный труд для исследования тонкостей языка Python. И хотя почти 800-страничный том выглядит устрашающе, вы не пожалеете о потраченном времени. Желаю удачи в вашем путешествии в мир программирования. Итак, за дело! 1 Слаткин Б. Секреты Python. 59 рекомендаций по написанию эффективного кода. 2 Бизли Д., Джонс Б. Python. Книга рецептов. 3 Рамальо Л. Python. К вершинам мастерства. ЧАСТЬ I ПЕРВЫЕ ШАГИ 1 Обработка ошибок и обращение за помощью Пожалуйста, не наделяйте компьютеры человеческими ка- чествами; их это очень сильно раздражает. Когда компьютер выдает сообщение об ошибке, это происходит вовсе не по- тому, что он на вас обиделся. Компьютеры — самые сложные инструменты, с которыми большинству из нас придется рабо- тать в жизни, и все же это всего лишь инструменты. Тем не менее легко обвинить в своих ошибках инструменты. Так как учиться про- граммировать многим из нас в основном приходится самостоятельно, часто мы чувствуем себя неудачниками — приходится неоднократно обращаться к интернету за информацией, хотя мы изучаем Python уже несколько месяцев. Но даже про- фессиональные разработчики обращаются к интернету или документации, чтобы найти ответы на вопросы по поводу программного обеспечения. Если вы не располагаете финансовыми или какими-то другими ресурсами, чтобы нанять преподавателя, который ответит на ваши вопросы, выбора не остается: ком- пьютер, поисковые системы в интернете и сила духа. К счастью, на ваши вопросы почти наверняка уже кто-нибудь отвечал. Умение самостоятельно искать ответы для программиста гораздо важнее знания любых алгоритмов или структур данных. В этой главе мы расскажем, как развить этот важнейший навык. Как понять сообщения об ошибках Python Когда программисты сталкиваются с лавиной технической информации в сообще- ниях об ошибках, им прежде всего хочется полностью ее проигнорировать. Но эти Как понять сообщения об ошибках Python 27 сообщения содержат ответ, что же не так с вашей программой. Процесс поиска информации состоит из двух этапов: анализа трассировки и поиска текста сообще- ния об ошибке в интернете. Анализ трассировки Программы Python аварийно завершаются, когда в коде возникает исключение, не обработанное командой except . В таком случае Python выдает сообщение об исключении и трассировку (также называемую трассировкой стека). Трассировка показывает, в какой точке вашей программы произошло исключение и последова- тельность вызовов функций, которые к этой точке привели. Чтобы потренироваться в чтении трассировки, введите следующую программу (она содержит ошибку) и сохраните ее под именем abcTraceback.py . Номера строк приведены только для удобства, они не являются частью программы. 1. def a(): 2. print('Start of a()') 3. b() # Вызов b(). ❶ 4. 5. def b(): 6. print('Start of b()') 7. c() # Вызов c(). ❷ 8. 9. def c(): 10. print('Start of c()') 11. 42 / 0 # Порождает ошибку деления на нуль. ❸ 12. 13. a() # Вызов a(). В этой программе функция a() вызывает b() ❶ , которая вызывает функцию c() ❷ Внутри c() выражение 42 / 0 ❸ вызывает ошибку деления на нуль. Если вы запу- стите эту программу, результат должен выглядеть так: Start of a() Start of b() Start of c() Traceback (most recent call last): File "abcTraceback.py", line 13, in a() # Call a(). File "abcTraceback.py", line 3, in a b() # Call b(). File "abcTraceback.py", line 7, in b c() # Call c(). File "abcTraceback.py", line 11, in c 42 / 0 # Порождает ошибку деления на нуль. ZeroDivisionError: division by zero 28 Глава 1.Обработка ошибок и обращение за помощью Проанализируем трассировку строку за строкой, начиная с этой: Traceback (most recent call last): Сообщение указывает, что далее идет трассировка. Текст most recent call last означает, что вызовы функций перечисляются по порядку, начиная с первой и за- канчивая самой последней. В следующей строке приводится вызов первой функции в трассировке: File "abcTraceback.py", line 13, in a() # Вызов a(). Следующие две строки содержат сводку кадра; в них выводится информация, храня- щаяся внутри объекта кадра. При вызове функции данные локальных переменных, а также точка в коде, в которую должно быть возвращено управление после вызова функции, сохраняются в объекте кадра. В объектах кадра хранятся локальные переменные и другие данные, связанные с вызовами функций. Объекты кадров создаются при вызове функции и уничтожаются при возвращении управления. В трассировке выводится сводка для каждого кадра на пути к фатальному сбою. Мы видим, что вызов функции в строке 13 находится в строке abcTraceback.py , а текст сообщает, что строка находится в глобальной области видимости. Далее строка 13 выводится с отступом из двух пробелов. В следующих четырех строках выводятся сводки следующих двух кадров: File "abcTraceback.py", line 3, in a b() # Call b(). File "abcTraceback.py", line 7, in b c() # Call c(). Из текста line 3, in a мы видим, что функция b() была вызвана в строке 3 внутри функции a() , что привело к вызову функции c() в строке 7 внутри функции b() Обратите внимание: вызовы print() в строках 2, 6 и 10 в трассировке не выводят- ся, несмотря на то что они были выполнены до вызовов функций. В трассировку включаются только строки с вызовами функций, приведших к исключению. В последней сводке кадра выводится строка, которая стала причиной необработан- ного исключения. За ней следует имя и сообщение исключения: File "abcTraceback.py", line 11, in c 42 / 0 # Порождает ошибку деления на нуль. ZeroDivisionError: division by zero Обратите внимание: номер строки в трассировке указывает, где была обнаружена ошибка. Источник ошибки находится где-то до этой строки. Как понять сообщения об ошибках Python 29 Сообщения об ошибках часто оказываются слишком короткими и невразуми- тельными; три слова «деление на нуль» ничего не скажут тому, кто не знает, что деление на нуль невозможно с точки зрения математики, и это распространенная программная ошибка. В этой программе найти ошибку несложно. Если взглянуть на строку кода в сводке кадра, становится ясно, что ошибка деления на нуль воз- никла из-за выражения 42 / 0 Но рассмотрим более сложный случай. Введите следующий фрагмент в текстовом редакторе и сохраните его под именем zeroDivideTraceback.py : def spam(number1, number2): return number1 / (number2 - 42) spam(101, 42) При запуске этой программы результат должен выглядеть так: Traceback (most recent call last): File "zeroDivideTraceback.py", line 4, in spam(101, 42) File "zeroDivideTraceback.py", line 2, in spam return number1 / (number2 - 42) ZeroDivisionError: division by zero Сообщение об ошибке то же, но деление на нуль в return number1 / (number2 - 42) не столь очевидно. По оператору / можно заключить, что выполняется деление, а выражение (number2 - 42) должно быть равно 0. Отсюда можно сделать вывод, что в функции spam() происходит сбой, когда параметр number2 равен 42. Иногда трассировка может сообщить, что ошибка находится в строке, расположен- ной после причины ошибки. Например, в следующей программе в первой строке отсутствует закрывающая круглая скобка: print('Hello.' print('How are you?') Но из сообщения об ошибке для этой программы следует, что проблема находится во второй строке: File "example.py", line 2 print('How are you?') ^ SyntaxError: invalid syntax Дело в том, что интерпретатор Python не заметил синтаксическую ошибку до того, как была прочитана вторая строка. Трассировка может сообщить, где обнаружена проблема, но это место не всегда то самое, где находится реальная причина ошибки. 30 Глава 1.Обработка ошибок и обращение за помощью Если сводка кадра не дает достаточной информации для обнаружения ошибки или если истинная причина ошибки находится в предыдущей строке, которая не приводится в трассировке, вам придется выполнять программу в пошаговом режиме в отладчике или просматривать сообщения в журнале. Все это потребует значительного времени. Поиск сообщения об ошибке в интернете иногда намного быстрее предоставит необходимую информацию о проблеме. Поиск сообщений об ошибках Часто сообщения об ошибках настолько коротки, что они даже не содержат полных предложений. Программисты регулярно сталкиваются с ними, поэтому они должны быть напоминаниями, а не исчерпывающими объяснениями. Если вы встречаете сообщение об ошибке впервые, скопируйте его в поисковую систему. С большой долей вероятности вы получите подробное описание того, что означает ошибка и каковы ее вероятные причины. На рис. 1.1 показаны результаты поиска по строке python "ZeroDivisionError: division by zero". Заключение сообщения об ошибке в кавычки помогает найти точную фразу, а добавление слова python способствует сужению поиска. Рис. 1.1. Копирование сообщения об ошибке в поисковую систему ускорит поиск объяснений и решений Предотвращение ошибок при помощи статического анализатора 31 Поиск сообщений об ошибках — вполне нормальное дело. Трудно ожидать, чтобы разработчик запомнил все возможные сообщения об ошибках для языка програм- мирования. Для профессионалов поиск ответов в интернете давно стал частью повседневной работы. Возможно, из поиска стоит исключить фрагменты, относящиеся непосредственно к вашему коду. Для примера рассмотрим следующее сообщение об ошибке: >>> print(employeRecord) Traceback (most recent call last): File " NameError: name 'employeRecord' is not defined ❶ >>> 42 - 'hello' Traceback (most recent call last): File " TypeError: unsupported operand type(s) for -: 'int' and 'str' ❷ В этом примере допущена опечатка в имени переменной employeRecord , что приво- дит к ошибке ❶ . Так как идентификатор employeRecord в сообщении NameError: name 'employeRecord' is not defined связан с вашим кодом, при поиске стоит использо- вать строку python "NameError: name" "is not defined" . В последней строке часть 'int' and 'str' в сообщении об ошибке ❷ явно относится к значениям 42 и 'hello' , так что усечение строки поиска до python "TypeError: unsupported operand type(s) for" позволит исключить фрагменты, относящиеся к вашему коду. Если поиск не даст полезных результатов, попробуйте включить полное сообщение об ошибке. Предотвращение ошибок при помощи статического анализатора Лучший способ исправления ошибок — не допускать их. Статические анализаторы (linters) — приложения, которые анализируют исходный код и предупреждают вас о потенциальных ошибках. Хотя статический анализатор не обнаруживает все ошибки, статический анализ (проверка исходного кода без его выполнения) помогает выявить типичные ошибки, возникающие из-за опечаток. (В главе 11 рассказано, как использовать рекомендации типов для статического анализа.) Мно- гие текстовые редакторы и интегрированные среды разработки (IDE) включают статический анализатор, который работает в фоновом режиме и способен выявлять проблемы в реальном времени (рис. 1.2). Почти моментальные уведомления от статического анализатора сильно повышают эффективность программирования. Без них вам пришлось бы запустить программу, увидеть произошедший сбой, прочитать трассировку, а затем найти строку в исход- ном коде, чтобы исправить ошибку. А если вы допустите несколько опечаток, то вам придется запускать цикл «запуск — исправление» для каждой из них, поскольку 32 Глава 1.Обработка ошибок и обращение за помощью он находит лишь по одной ошибке за раз. Статический анализ способен выявить сразу несколько ошибок, и это происходит прямо в редакторе — вы видите строки с ошибками. Рис. 1.2. Статический анализатор указывает на не определенную переменную в Mu (наверху), PyCharm (в середине) и Sublime Text (внизу) Возможно, ваш редактор или IDE не поддерживает статического анализа, но если в нем поддерживаются плагины, статический анализатор почти всегда можно под- ключить. Обычно такие плагины используют для проведения статического анализа модуль Pylakes или какой-то другой. Чтобы установить Pylakes, откройте страницу https://pypi.org/project/pylakes/ или выполните команду pip install --user pyflakes . Поверьте, дело того стоит. ПРИМЕЧАНИЕ В системе Windows можно выполнять команды python и pip. Но в macOS и Linux эти имена подходят только для Python версии 2, и вместо них следует использовать команды python3 и pip3. Помните об этом, когда вы встречаете python или pip в книге. В IDLE (среда, включенная в поставку Python) нет ни статического анализатора, ни возможности его установки. Как обратиться за помощью по программированию 33 Как обратиться за помощью по программированию Если поиск в интернете и статические анализаторы не помогли с решением вашей проблемы, стоит обратиться за помощью к сообществу в интернете. Но существует определенный этикет при обращениях за советом. Если опытные разработчики готовы бесплатно ответить на ваш вопрос, позаботьтесь о том, чтобы эффективно использовать их время. Обращение за помощью к незнакомым людям всегда должно быть последней мерой. Могут пройти часы и дни, пока кто-нибудь ответит на ваш вопрос — если вы во- обще получите ответ. Гораздо быстрее поискать в интернете других людей, которые уже ответили на ваш вопрос, и прочитать их ответы. Электронная документация и поисковые системы создавались как раз для того, чтобы облегчить поиск ответов, за которыми в противном случае пришлось бы обращаться к людям. Но если все иные возможности исчерпаны и вам все-таки приходится обращаться с вопросом к людям, старайтесь избегать некоторых распространенных ошибок. Не спрашивайте, можно ли задать вопрос, а просто задайте его. Не обозначайте суть вопроса намеками, формулируйте конкретно. Не задавайте вопрос на неподходящем форуме или веб-сайте. Не используйте неконкретный заголовок или тему сообщения — например, «У меня проблема» или «Помогите, пожалуйста». Не пишите «Моя программа не работает», объясните, как она должна ра ботать. Не храните в секрете полные сообщения об ошибках. Не ленитесь опубликовать ваш код. Не приводите плохо отформатированный код. Не замалчивайте, что вы уже пытались сделать. Не скрывайте информацию об операционной системе или версии. Не просите написать программу за вас. Этот список приведен не просто для красоты; неправильная коммуникация мешает людям помочь вам. Первое, о чем следует просить, — запустить код и попытаться воспроизвести вашу проблему. Для этого тому, кто решит вам помочь, понадобится как можно больше информации о вашем коде, компьютере и намерениях. Гораздо чаще информации оказывается слишком мало, а не слишком много. В нескольких следующих разделах я расскажу, что можно сделать для предотвращения распро- страненных ошибок. Мои рекомендации относятся к случаю, когда вы публикуете свои вопросы на интернет-форуме, однако они актуальны и тогда, когда вы отправ- ляете вопросы адресно одному или нескольким людям. |