ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 03.12.2023
Просмотров: 392
Скачиваний: 1
ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
СОДЕРЖАНИЕ
112
Глава 5.Поиск запахов в коде
Итоги
Некие признаки, или запахи кода, указывают на то, что, вероятно, этот код можно написать лучше. Они не всегда требуют изменений, но лучше присмотреться к коду еще раз. Самый распространенный запах кода — дублирование — понуждает про- граммиста к тому, чтобы разместить код в функции или в цикле. Это гарантирует, что изменения будет достаточно внести только в одном месте. Еще один признак возможной проблемы — «магические» числа: загадочные значения, которые можно заменить константами с содержательными именами. Также стоит упомянуть о за- комментированном и мертвом коде, который никогда не выполняется компьютером.
Он может сбить с толку программистов, которые впоследствии будут его читать.
Лучше удалить такие фрагменты полностью и воспользоваться системой контроля версий (такой как Git), если позднее вам потребуется снова включить их в свою программу.
Механизм отладочного вывода использует вызовы print()
для вывода отладочной информации. Несмотря на простоту такого подхода, в долгосрочной перспективе для диагностики ошибок лучше положиться на отладчик и журнальные файлы.
Переменные с числовыми суффиксами (
x1
, x2
, x3
и т. д.) стоит заменить одной переменной, содержащей список. В отличие от таких языков, как Java, в Python для группировки функций используются не классы, а модули. Класс, содержащий только один метод или только статические методы, можно также рассматривать как запах кода, предполагающий, что код лучше разместить в модуле, а не в классе.
И хотя списковые включения предоставляют компактный механизм создания спи- сковых значений, вложенные списковые включения обычно очень плохо читаются.
Кроме того, любые исключения, обрабатываемые пустыми блоками except
, указы- вают на то, что вы просто игнорируете ошибку, вместо того чтобы обработать ее.
Короткое, невразумительное сообщение об ошибке так же бесполезно для пользо- вателя, как и отсутствие сообщения.
Наряду с этими признаками возможных проблем стоит упомянуть и мифы о них: советы по программированию, которые перестали быть актуальными или со време- нем стали нерациональными. Это и размещение только одной команды return или блока try
- except в каждой функции, полный отказ от использования аргументов- флагов и глобальных переменных и вера в то, что комментарии в коде излишни.
Конечно, как это обычно бывает со всеми советами в области программирования, запахи кода, о которых здесь шла речь, могут не пригодиться вам при реализации вашего проекта или не соответствовать вашим предпочтениям. Все весьма субъек- тивно. С появлением практического опыта вы сами сделаете выводы относительно того, какой код хорошо читается или является надежным, но, надеюсь, что вам все- таки пригодятся краткие рекомендации, изложенные в этой главе.
6
Написание питонического кода
Мощный — бессмысленный эпитет для языков программиро- вания. Каждый язык программирования описывает себя как мощный. Официальный учебник Python начинается с фразы
«Python — доступный и мощный язык программирования».
Но не существует алгоритма, который можно реализовать на одном языке и нельзя — на других, и нет единиц для оценки
«мощи» языка программирования (хотя, конечно, можно выбрать в качестве параметра громкость изложения программистами аргументов в пользу своего любимого языка).
Но у каждого языка имеются свои паттерны проектирования и скрытые ловушки, которые составляют его сильные и слабые стороны. Чтобы писать код Python на профессиональном уровне, недостаточно знать синтаксис и стандартную библио- теку. Необходимо изучить идиомы, то есть практики программирования, специ- фические для Python. Некоторые языковые средства Python позволяют отлично писать код в стиле, который называется питоническим.
В этой главе я покажу некоторые популярные способы написания идиоматиче- ского кода Python и его непитонических аналогов. Вопрос о том, какой код счи- тать питоническим, как правило, каждый программист решает сам, но о наиболее распространенных приемах и методах я расскажу ниже. Опытные программисты
Python часто применяют эти приемы, и, если вы будете знать их, это поможет вам идентифицировать их в реальном коде.
«Дзен Python»
«Дзен Python» — набор из 20 руководящих принципов проектирования языка
Python и программ Python, написанный Тимом Петерсом. Вы не обязаны следовать
114
Глава 6.Написание питонического кода всем этим принципам, но их стоит держать в голове. Кроме того, «Дзен Python» — это скрытая шутка, которая появляется при выполнении команды import this
:
>>>
1 ... 6 7 8 9 10 11 12 13 ... 40
import this
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
--snip--
ПРИМЕЧАНИЕ
Как ни странно, записаны только 19 принципов. Говорят, Гвидо ван Россум, создатель
Python, заявил, что отсутствующий 20-й пункт был «странной шуткой Тима Петерса, по- нятной только посвященным». Тим оставил в списке пустое место и предложил заполнить его Гвидо, но похоже, у того так и не нашлось времени.
В конечном итоге эти тезисы — всего лишь изложение мнения, с которым про- граммисты могут соглашаться или не соглашаться. Как и во всех хороших сводах нравственных норм, они противоречат друг другу, что обеспечивает наибольшую гибкость в их реализации. Моя интерпретация этих тезисов изложена ниже.
Красивое лучше, чем уродливое. Красивым обычно считается код, который легко читается и воспринимается. Нередко программисты пишут код слишком быстро, не заботясь об удобочитаемости. Компьютер выполнит нечитаемый код, но у про- граммистов возникнут сложности с его сопровождением и отладкой. Красота — по- нятие субъективное, но код, при написании которого программист не позаботился о том, как он будет читаться, другим часто кажется уродливым. Одна из причин популярности Python как раз связана с тем, что его синтаксис не загромождается загадочными знаками препинания, как в других языках, что упрощает работу с ним.
Явное лучше, чем неявное. Если бы в качестве пояснения данного правила я сказал
«это очевидно», это было бы ужасно. Так и в коде лучше выражаться развернуто и явно. Не стоит прятать функциональность в невнятном коде, понимание которого требует знания всех тонкостей языка.
Простое лучше, чем сложное. Сложное лучше, чем запутанное. Эти два утверж- дения напоминают нам, что все можно строить как простыми, так и сложными средствами. Если перед вами стоит простая задача, для решения которой нужна лопата, использовать 50-тонный гидравлический бульдозер неэффективно. Но для выполнения грандиозной задачи сложность управления одним бульдозером ничто по сравнению с координацией команды из 100 землекопов. Отдавайте предпочтение простоте перед сложностью, но знайте границы простоты.
Плоское лучше, чем вложенное. Программисты любят делить свой код на ка- тегории, особенно если те содержат подкатегории, которые содержат другие
«Дзен Python»
115
подкатегории. Эти иерархии часто продуцируют не столько организацию, сколько бюрократизм. Ничто не мешает вам написать код, содержащийся всего в одной структуре данных или модуле верхнего уровня. Если в вашем коде часто встреча- ются конструкции вида spam.eggs.bacon.ham()
или spam['eggs']['bacon']['ham']
, вы его переусложнили.
Разреженное лучше, чем плотное. Программисты любят втискивать макси- мум функциональности в минимальный объем кода, как в следующей строке: print('\n'.join("%i bytes
=
%i bits which has
%i possiblevalues."
%
(j,
j*8,
256**j-1)
for j
in
(1
<<
i for i
in range(8))))
. Хотя такой код наверняка произ- ведет впечатление на друзей, он приведет в ярость коллег, которым придется в нем разбираться. Не стремитесь к тому, чтобы ваш код делал много всего и сразу. Код, распределенный по нескольким строкам, часто читается проще, чем плотные одно- строчные конструкции. Это правило означает приблизительно то же, что и «простое лучше, чем сложное».
Удобочитаемость важна. Хотя имя strcmp()
наверняка означает «сравнение строк» для тех, кто программировал на C с 1970-х годов, у современных компьютеров хватает памяти для полных имен функций. Не пропускайте буквы в именах и не пишите слишком лаконичный код. Не жалейте времени на поиск содержательных, конкретных имен для ваших переменных и функций. Пустая строка между раз- делами кода решает ту же задачу, что и разбивка на абзацы в книге: она сообщает читателю, какие части должны читаться вместе. Это правило означает приблизи- тельно то же, что и «красивое лучше, чем уродливое».
Особые случаи не настолько особые, чтобы нарушать правила. При этом прак-
тичность важнее безупречности. Эти два афоризма противоречат друг другу.
В программировании полно передовых практик, которые программистам следует использовать в своем коде. Желание обойти эти приемы ради быстрого хитроум- ного трюка соблазнительно, но иногда приводит к беспорядочному клубку непо- следовательного и нечитаемого кода. С другой стороны, фанатичное следование правилам может стать причиной абстрактного, неудобочитаемого кода. Например, в Java попытка написать весь код в парадигме объектно-ориентированного про- граммирования часто приводит к использованию большого объема шаблонов даже в самой мелкой программе. С опытом вы научитесь проходить по узкой кромке между этими двумя положениями. А со временем не только узнаете правила, но и поймете, когда их можно нарушать.
Ошибки никогда не должны замалчиваться. Если только они не замалчиваются
явно. Хотя программисты часто игнорируют сообщения об ошибках, это не значит, что программа должна перестать их выдавать. Чаще всего ошибки замалчиваются, когда функции возвращают коды ошибок или
None вместо выдачи исключений. Эти два тезиса утверждают, что лучше программировать с расчетом на быстрый сбой
116
Глава 6.Написание питонического кода и аварийное завершение, чем на замалчивание ошибки с продолжением выполне- ния. Ошибки, которые неизбежно возникнут позднее, создадут больше проблем с отладкой, потому что они проявят себя далеко от причины, их вызвавшей. Хотя вы можете взять за правило явно игнорировать ошибки, возникающие в вашей программе, убедитесь, что это ваше сознательное решение.
Столкнувшись с неоднозначностью, боритесь с искушением угадать. Компьюте- ры делают людей суеверными: чтобы изгнать демонов из наших компьютеров, мы выполняем священный ритуал, перезагружая их. Предполагается, что это решит любую непонятную проблему. Однако в компьютерах нет ничего волшебного.
Если код не работает, тому есть причина, и проблему можно решить, только при- звав на помощь критическое мышление. Боритесь с искушением искать причину наугад, пока что-то не заработает; часто вы всего лишь маскируете проблему, а не решаете ее.
Должен быть один — и желательно только один — очевидный способ сделать это.
Этот тезис напрямую противоречит девизу языка программирования Perl: «Это можно сделать разными способами!». Как выясняется, возможность написать код для решения одной задачи тремя-четырьмя разными способами становится пал- кой о двух концах: у вас появляется большая гибкость в написании кода, но зато вам придется изучать все возможные способы его написания, чтобы читать чужой код. Гибкость не оправдывает лишних усилий, которые потребуются для изучения языка программирования.
Хотя это может быть и не очевидно, если только вы не голландец. Это шутка. Ибо
Гвидо ван Россум, создатель Python, — голландец.
Сейчас лучше, чем никогда. Хотя никогда зачастую лучше, чем *прямо* сейчас.
Это о том, что код, который работает медленно, очевидно хуже, чем тот, который работает быстро. Но лучше дождаться завершения программы, чем завершить ее слишком рано с неправильными результатами.
Если реализацию сложно объяснить, идея плоха. Если реализацию легко объяс-
нить, возможно, идея хороша. Многие вещи усложняются со временем: налоговое законодательство, романтические отношения, книги по программированию на язы- ке Python. То же можно сказать и о программах. Эти два положения напоминают нам: если код настолько сложен, что программист не сможет его понять и отладить, это плохой код. Но если код объясняется легко, это не обязательно означает, что он хорош. К сожалению, понять, как сделать код простым настолько, насколько это возможно, и ни на йоту проще, достаточно сложно.
Пространства имен — отличная штука. Сделаем их побольше! Пространства имен представляют собой изолированные контейнеры для идентификаторов, предот- вращающие конфликты имен. Например, встроенная функция open()
и функция