Рефакторинг — это процесс обновления существующего кода без изменения его функционала. Существует множество причин рефакторить код, включая производительность, читаемость и масштабируемость в будущем.
Рефакторинг — это важная часть процесса для любого кодера, не только для продвинутых разработчиков. Для менее опытной аудитории рефакторинг является прекрасной возможностью изучать и отрабатывать новые приёмы, повышать свой уровень от сделано до сделано правильно!
Рассмотрим пять простых способов рефакторинга кода для начинающих в Python с пояснениями преимуществ и демонстрацией кода до и после.
Первый и, возможно, наиважнейший рефакторинг, который можно сделать, это определить функции для повторяющихся задач. Функция — это заданный набор операторов, выполняющихся с использованием имени функции, известного как вызов функции.
Функции предоставляют множество преимуществ, но с точки зрения рефакторинга сокращается объём кода, улучшается читаемость. Кроме того, если нужно обновить задачу, делать это понадобится только на одном участке — в определении функции.
Давайте рассмотрим пример, где нужно запросить длину и ширину прямоугольника для вычисления его площади.
Доwhile True:
length = int(input("Enter the length: "))
if length > 0:
break
while True:
width = int(input("Enter the width: "))
if length > 0:
break
print("The area is", length * width)
Заметьте, что два блока почти идентичны. А что, если понадобится вычислить объём куба? Скорее всего мы скопируем цикл while, изменив имя переменной и приглашение к вводу.
Послеdef input_positive_integer(prompt):
while True:
input_value = int(input(prompt))
if input_value > 0:
return input_value
length = input_positive_integer("Enter the length: ")
width = input_positive_integer("Enter the width: ")
print("The area is", length * width)
Теперь код проще читать, кроме того мы сэкономили несколько строк кода. Что ещё лучше, в будущем можно будет легко использовать эту функцию и вставлять её в другой скрипт, экономя время.
Конструктор списков — один из самых легендарных конструкторов Python. Конструктор списков является более чистой и быстрой реализацией в сравнении с многими простыми циклами for.
Существует множество преимуществ рефакторинга циклов for в конструкторы списков: код будет выполняться быстрее, существующие данные не будут меняться, кроме того, конструктор списков проще читать, как только вы к нему привыкаете.
Давайте рассмотрим два примера, один простой и второй немного посложнее.
В первом примере выберем нечётные числа из списка целых чисел.
Доmy_numbers = [1,2,3,4,5]
odd_numbers = []
for item in my_numbers:
if item % 2 == 1:
odd_numbers.append(item)
print(odd_numbers) # [1, 3, 5]
В этом примере запустим цикл в my_numbers
и используем оператор вычисления остатка, чтобы определить, нужно ли вставлять элемент в odd_numbers
.
my_numbers = [1,2,3,4,5]
odd_numbers = [item for item in my_numbers if item % 2 == 1]
Подведём итог в этом примере: конструктор списков — это передача элементов в odd_numbers
, перебор my_numbers
, выполнение return (первый item
) и применение оператора if для фильтрации.
Можно создавать более сложные конструкторы списков, что даёт большие преимущества. Во втором примере предположим, что у нас есть двумерная матрица целых чисел и каждое значение мы хотим возвести в квадрат.
Доmatrix = [[1,2,3],[4,5,6],[7,8,9]]
squared_matrix = []
for row in matrix:
line = []
for item in row:
line.append(item ** 2)
squared_matrix.append(line)
print(squared_matrix)
# [[1, 4, 9], [16, 25, 36], [49, 64, 81]]
Мы должны использовать вложенный цикл for вместе с временной переменной для хранения каждой строки перед вставкой в окончательную переменную.
После рефакторингаmatrix = [[1,2,3],[4,5,6],[7,8,9]]
squared_matrix = [
[
item ** 2
for item in row
]
for row in matrix
]
print(squared_matrix)
# [[1, 4, 9], [16, 25, 36], [49, 64, 81]]
Здесь немного расширено описание для лучшей читаемости, но все вычисления и вложенный цикл for обрабатываются в одном присвоении.
Присвоение одного из двух значений может быть обработано с помощью простого оператора if:
if args['website']:
website = args['website']
else:
website = "https://nuancesprog.ru"
Эти типы присвоений “или-или” традиционно могут выполняться с помощью условного оператора, объединяющего присвоения в один.
До website = args['website'] if args['website'] else "https://nuancesprog.ru"Структура условного оператора такова:
value if true | expression | value if falseКогда выражение должно оценить, приводит ли “value-if-true” к булеву значению True
, логический оператор OR может упростить трудно читаемый условный оператор.
Логический оператор OR пытается присвоить первое значение. Если первое значение приводит к False
—None, пустая переменная и т.д.—используется второе значение.
Этот код значительно проще читать, он позволяет эффективно устанавливать значение по умолчанию при присвоении переменной.
Цикл for в Python может сбивать с толку, особенно, если вы привыкли работать с другими языками программирования. Вашим первым порывом будет создать индексную переменную и использовать её для перебора списка.
В результате часто используется функция range()
. Этот приём не “в стиле” Python, в отличие от руководства по стилю и проверенных приёмов. Подробнее вы можете прочесть в моей статье “Перестаньте использовать range() в цикле for в Python”.
Если вам очень нужны индексы каждого значения, используйте функцию enumerate()
: перебор будет производиться по фактическому списку, и независимая переменная будет не нужна.
races = ["Terran", "Protoss", "Zerg"]
for i in range(len(races)):
print(i+1, races[i])
# 1 Terran
# 2 Protoss
# 3 Zerg
Использование индекса в исходном списке приводит к неудачным методам, таким как обновление исходных значений, кроме того, читать код становится труднее… особенно в сложных вложенных структурах данных. Также мы вынуждены вручную управлять индексом, чтобы изменять значения порядковых номеров.
После рефакторингаraces = ["Terran", "Protoss", "Zerg"]
for i, race in enumerate(races, 1):
print(i, race)
# 1 Terran
# 2 Protoss
# 3 Zerg
Функция enumerate()
принимает два аргумента: итерируемое и начальное значение счёта, а возвращает текущее порядковое значение и элемент в итерируемом. Примечание: временная переменная счёта идёт первой в цикле for, а начальное значение счёта идёт вторым в вызове функции. Это распространённая ошибка.
Возьмите за правило пересматривать и рефакторить свой код. Ваша разработка будет медленнее без актуальных навыков и оптимизированных методов программирования.
Перевод статьи Jonathan Hsu: 4 Simple Ways to Refactor Your Python Code
Комментарии