Динамически вызывать функцию, перечислять функции с определенной частью их имени и т. Д.
Эффективный рефакторинг существующего кода - это искусство. Если вы когда-либо унаследовали чужой код или даже через некоторое время оглянулись на свой собственный, вы знаете, насколько сложным может быть этот процесс. Часто функции создаются и ошибки исправляются в сжатые сроки, что может привести к небрежному и неэффективному коду.
Это совершенно нормально. Вам разрешено время от времени использовать некоторые неверные коды. Крайне важно, чтобы вы могли идентифицировать плохой код и всегда возвращаться, чтобы исправить его.
В этой статье мы рассмотрим некоторые небольшие сегменты кода Python, которые упрощают рефакторинг для получения более чистого кода. В большинстве случаев они используют простые стандартные библиотечные функции и не скрывают намерений, стоящих за чрезвычайно сложными алгоритмами или плотными однострочниками. При рефакторинге кода вам нужен хороший баланс между краткостью и удобочитаемостью. Давайте посмотрим на несколько примеров.
Динамический вызов функций
def call_func(name): klass = MyClass() return getattr(klass, name)() call_func('function_name')
Если вы встретите участки кода, в которых вы не обязательно узнаете имя функции, которую хотите вызвать, на потом, это ответ. Используя встроенную функцию Python getattr
, вы можете вызывать функцию по имени, используя строку. Это отлично подходит для уменьшения количества тесно связанного кода и улучшения расширяемости. Если вы уменьшите количество жестко запрограммированных имен функций и обеспечите большую гибкость, то есть большая вероятность, что ваш код будет меньше ломаться.
Использование этого простого метода также снижает накладные расходы других разработчиков на добавление функций в существующий код. Если все, что вам нужно сделать, это добавить новую функцию в класс, и она сразу станет пригодной для использования, что снижает сложность и упрощает работу с кодом.
Подробнее о функции getattr
вы можете прочитать в документации.
Использование деструктурирующего присваивания
var_one, var_two = [1, 2]
Вы, наверное, слышали об этой концепции миллион раз раньше, но стоит повторить еще раз: используйте деструктурирующее присваивание там, где это возможно, чтобы отображать значения и более четко передавать намерения. Когда вы получаете доступ к списку или массиву по значениям индекса, вы непреднамеренно скрываете свое намерение. Обращение к значениям по четкому имени переменной, присвоенному посредством деструктурирующего присваивания, упрощает чтение вашего кода.
В приведенном ниже примере у нас есть некоторые данные о человеке в списке. Эти данные включают основную информацию, такую как имя, возраст и профессия человека. Давайте предположим для этого примера, что это часть ответа, который мы получили на веб-запрос, и что нам нужно будет проанализировать несколько ответов точно так же. Если бы мы хотели получить имя человека, мы могли бы просто получить к нему доступ по значению индекса:
person = ['Bill', 26, 'Programmer'] print(person[0])
Это небрежно и скрывает намерение, если вы когда-либо упоминали его более одного раза. Ссылки на person[0]
повсюду в вашем коде затруднят интерпретацию того, какое значение должно быть. Для этого есть очень простое исправление, которое не скрывает ваши намерения и делает ваш код более читабельным. Просто назначьте это переменной и, если возможно, также деструктурируйте весь список на переменные с соответствующими именами. Давайте посмотрим на пример применения этого на практике:
person = ['Bill', 26, 'Programmer'] name, age, profession = person print(name)
Теперь, если вам понадобится ссылаться на имя позже, вы сделаете это через именованную переменную, а не через значение индекса. Это хорошо работает для данных ответа, структура которых вам наверняка известна. Пока информация о человеке всегда находится в одном и том же порядке, вы можете деструктурировать и назначать все снова и снова, чтобы избежать использования значений индекса.
Список функций с определенным шаблоном
В этом примере предположим, что у нас есть класс, содержащий большое количество функций. Некоторые из этих функций служат для специальных целей и должны быть динамически доступны. Мы хотим, чтобы любая специальная функция, которую мы добавляем в этот класс, немедленно обрабатывалась остальной частью нашего кода, чтобы она сразу же начала работать. Один из способов добиться этого - просто использовать dir
в содержащем классе.
Если вы передадите класс dir
, он перечислит все атрибуты для этого объекта. Сюда входят названия его функций. Путем фильтрации префикса, суффикса или ключевого слова, включенного в имя строки, мы можем сгруппировать функции этого класса по различным категориям. Это позволяет нам «подбирать» новые функции, имена которых включают ключевое слово, и либо вызывать их все, либо выполнять с ними другую логику позже в коде.
Узнайте больше о встроенной функции dir
в документации.
Передача нескольких аргументов функций как Dict
Есть большая вероятность, что вы уже сталкивались с чем-то подобным раньше при рефакторинге кода:
Хотя определенные форматы этого стиля отступа могут быть технически разрешены в PEP8, мне лично не нравится смотреть на аргументы функций с сильным отступом. Вы вынуждены переводить взгляд полностью вправо, некоторые IDE плохо справляются с этим отступом, и использование этого стиля препятствует будущей расширяемости.
Один из вариантов улучшения читабельности и повторного использования при большом количестве аргументов функции - передать их в форме dict. Вот пример этого:
Использование оператора **
в dict при передаче dict функции позволяет успешно распаковать все аргументы (вместо случайной передачи самого объекта dict). Хотя этот метод добавляет еще одну переменную и отдельную структуру данных, он улучшает общую читаемость при большом количестве аргументов. Перемещение вызова функции или ссылка на несколько вызовов одной и той же функции с одинаковыми (или слегка измененными) аргументами теперь становится бесконечно проще и требует меньших общих изменений.
Заключение
Спасибо за чтение! Я надеюсь, что эти фрагменты кода помогут повысить вашу эффективность в следующий раз, когда вы обнаружите, что разбираете код Python на части.