Читая плохой код, вы можете узнать больше, чем хороший код

Я кодирую на Python более шести лет, и до сих пор я все еще изучаю новые концепции и передовые методы для улучшения качества кода.

Когда я только начинал, понять, как что-то делать, было непросто: мне пришлось выучить это на собственном горьком опыте.

В этом посте я решил составить список из 18 антипаттернов и худших практик Python, о которых я хотел бы знать раньше: это может сэкономить вам время и ускорить отладку ваших проектов.

Этот список основан на обсуждениях с коллегами-разработчиками Python, экспертами по программированию и долгих погружениях в темы Reddit.
Но это не исчерпывающий список: если вы хотите углубиться в эту тему (интересная, клянусь, ) Я привел несколько ссылок в конце.

Давай посмотрим сейчас 🚀

0-прежде чем начать, что за антипаттерн?

Антишаблоны - это определенные шаблоны в разработке программного обеспечения, которые считаются плохой практикой программирования.

В отличие от шаблонов проектирования, которые представляют собой общие подходы к общим проблемам, которые были формализованы и обычно считаются хорошей практикой разработки, анти-шаблоны являются противоположными и нежелательными.

Антишаблоны делают код трудным для чтения, сложным в обслуживании, медленным, чрезмерно сложным, нестабильным, подверженным ошибкам и с потенциальными проблемами безопасности.

Введение антипаттернов происходит по многим причинам:

  • отсутствие проверки кода
  • готовность опробовать "крутые" вещи, когда простые вещи могут помочь
  • не использовать правильные инструменты (линтеры кода и средства форматирования в соответствии с соглашениями PEP8, генераторы строк документации, IDE, поддерживающие автозаполнение, и многие другие)
  • или просто не зная лучшей альтернативы, что нормально, если вы учитесь и растете

Антипаттерны можно разделить на одну или несколько из следующих категорий:

  1. Корректность: анти-шаблоны, которые буквально сломают ваш код или заставят его делать неправильные вещи.
  2. Ремонтопригодность: антишаблоны, затрудняющие поддержку или расширение вашего кода.
  3. Читаемость. Антишаблоны, затрудняющие чтение или понимание вашего кода.
  4. Производительность: антишаблоны, которые излишне замедляют ваш код.
  5. Безопасность: защита от шаблонов, создающих угрозу безопасности вашей программы.

Давайте теперь посмотрим на этот список из 18 антипаттернов. Некоторые из них подпадают под одну или несколько категорий.

1 - Использование неявных имен переменных

Имена переменных всегда должны быть описательными, чтобы обеспечивать минимальный контекст: имя переменной должно словами сообщать вам, что обозначает переменная.

Это упрощает понимание кода другими разработчиками и упрощает отладку для вас.

СОВЕТ 👉: не бойтесь использовать длинные имена переменных для наглядности: современные IDE, такие как VSCode и Pycharm, обеспечивают быстрое автозаполнение.

2 - Игнорирование комментариев

Недокументированный код - это кошмар. Вот люди, которые могут жаловаться на это:

  • через 6 месяцев, когда вы забудете, зачем вы написали эту строчку кода
  • любой ваш коллега, который возьмет на себя проект

Код всегда должен четко указывать, что он делает, а комментарии должны разъяснять, почему вы это делаете. В то же время, комментируя свой код, будьте лаконичны. Если ваш код не требует пояснений, комментарии не нужны.

СОВЕТ 👉: если вы используете VSCode, вы можете ускорить создание строк документации с помощью этого расширения, которое автоматически генерирует шаблон комментария для ваших классов и функций.

3 - Забыть обновить комментарии

Комментарии, противоречащие коду, хуже, чем их отсутствие.

Это происходит чаще, чем вы думаете: когда вы спешите и вам нужно исправить неработающий производственный код, вы сделаете это, не найдя времени на обновление старых комментариев.

Устаревший комментарий вводит в заблуждение всех, кто работает над кодом.

Всегда есть время обновить комментарии.

4 - Использование CamelCase в именах функций

Это больше похоже на соглашение: руководство по стилю PEP 8 рекомендует, чтобы имена функций всегда были в нижнем регистре, а слова разделялись символами подчеркивания.

5 - Отсутствие итерации непосредственно по элементам итератора

Это довольно распространенный антипаттерн. Вам не обязательно перебирать индексы элементов в итераторе, если они вам не нужны. Вы можете выполнять итерацию непосредственно по элементам.

Это делает ваш код более питоническим.

6 - Не использовать enumerate, когда вам нужен элемент и его индекс одновременно

Если вам нужно получить доступ к элементу и его индексу одновременно при повторении итератора, используйте enumerate.

7 - Не использовать zip для перебора пар списков

zip - полезная встроенная функция, которая позволяет создавать список кортежей из двух итераторов. первый элемент каждого кортежа поступает от первого итератора, а второй элемент - от второго итератора.

zip может быть полезен, если вы хотите перебрать два или более итератора одновременно.

8 - Не использовать диспетчер контекста при чтении или записи файлов

Когда вы используете open без диспетчера контекста и перед закрытием файла возникает какое-то исключение (закрытие файла - это то, что вы должны помнить, открывая файл таким образом), могут возникнуть проблемы с памятью, и файл может быть поврежден в процессе.

Когда вы используете with для открытия файла и возникает исключение, Python гарантирует, что файл закрыт.

9 - Использование in, чтобы проверить, содержится ли элемент в (большом) списке

Проверка наличия элемента в списке с помощью оператора in может быть медленной для больших списков. Вместо этого рассмотрите возможность использования набора или пополам.

Вот сравнение трех методов:

→ источник: StackOverflow

10 - Передача в функции изменяемых аргументов по умолчанию (т.е. пустой список)

Вот забавная вещь в Python, которая может приводить к скрытым ошибкам и скрытым ошибкам: аргументы по умолчанию оцениваются один раз, когда функция определена, а не каждый раз, когда функция вызывается.

Это означает, что если вы используете изменяемый аргумент по умолчанию (например, список) и измените его, вы также измените этот объект для всех будущих вызовов функции.

Чтобы избежать этой проблемы, вы можете установить для аргумента по умолчанию to значение None:

  • если функция с вызывается несколько раз с to, установленным на None, создайте новый пустой список и каждый раз добавляйте к нему элемент
  • когда вы передаете список в to, вы добавляете к нему элемент. Поскольку это не аргумент функции по умолчанию, это работает хорошо.

11 - Возврат разных типов в одной функции

При попытке обработать специальные пользовательские вводы, которые могут вызывать ошибки, вы можете иногда вводить None в качестве вывода. Это делает ваш код непоследовательным, поскольку ваша функция теперь возвращает как минимум два типа: исходный тип, который вы планировали, и тип NoneType.

Это затрудняет последующее тестирование и отладку.

Вместо того, чтобы возвращать None, вы можете вызвать ошибку, а затем отловить ее.

12.Использование циклов while, когда простые циклы for помогут

Вам не нужно использовать цикл while, если вы заранее знаете количество итераций.

13 - Использование составных и вложенных операторов if

Сложенные и вложенные операторы if затрудняют соблюдение логики кода.

Вместо условий вложения их можно комбинировать с логическими операторами.

14 - Использование глобальных переменных

Избегайте глобальных переменных, таких как чума. Они являются источником многих ошибок. К ним можно получить одновременный доступ из нескольких разделов программы, что может привести к ошибкам.

Типичная ошибка, возникающая при использовании глобальных переменных, - это когда функция получает доступ к своим значениям до того, как другая нуждается в правильном обновлении.

15 - Не использовать get () для возврата значений по умолчанию из словаря

Когда вы используете get, python проверяет, существует ли указанный ключ в словаре. Если да, то get() возвращает значение этого ключа. Если ключ не существует, get() возвращает значение, указанное во втором аргументе.

16. Использование блоков try / except, которые не обрабатывают исключения осмысленно

Следует избегать использования блока try / except и игнорирования исключения путем его передачи (например).

17 - гордо печатать: из модуля импорта *

Импорт всегда должен быть конкретным. Импорт * из модуля - очень плохая практика, которая загрязняет пространство имен.

18 - Все переосмыслили

Вам не всегда нужны занятия. Простые функции могут быть очень полезными.

Классы часто имеют методы, которые являются функциями, связанными с определенным классом, и делают вещи, связанные с тем, чем является класс, но если все, что вам нужно, это что-то делать, функция - это все, что вам нужно.

По сути, класс - это способ группировки функций (как методов) и данных (как свойств) в логическую единицу, вращающуюся вокруг определенного рода вещей. Если вам не нужна такая группировка, не нужно создавать класс.

Спасибо за чтение 🙏

Надеюсь, это было вам полезно. Если вы знаете другие популярные антипаттерны Python, не стесняйтесь указывать мне на них в комментариях.

Удачного взлома, до следующего раза 👋

Ресурсы:

Впервые на Medium? Вы можете подписаться за 5 долларов в месяц и разблокировать неограниченное количество статей - нажмите здесь.