8 быстрых советов по рефакторингу Python для более чистого и более Pythonic-кода.

 

1. Объединить добавление в объявление списка

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

players = []
players.append("Patrick")
players.append("Max")
players.append("Jessi")

# -> refactor
players = ["Patrick", "Max", "Jessi"]

То же самое относится и к заполнению других типов коллекций, таких как наборы и словари.

2. Используйте items() для прямой распаковки значений словаря

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

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

teams_by_color = {"blue": ["Patrick", "Jessi"]}

for team_color in teams_by_color:
    players = teams_by_color[team_color]
    if is_winning(team_color):
        advance_level(players)

# -> refactor
for team_color, players in teams_by_color.items():
    if is_winning(team_color):
        advance_level(players)

 

3. Замените диапазон (длина) перечислением

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

for i in range(len(players)):
    print(i, players[i])

# -> refactor
for i, player in enumerate(players):
    print(i, player)

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

for i, player in enumerate(players, start=1):
    print(i, player)

 

4. Замените ручной счетчик циклов вызовом перечисления

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

i = 0
for player in players:
    print(i, player)
    i += 1

# -> refactor
for i, player in enumerate(players):
    print(i, player)

 

4.1 Не обновлять счетчик вручную

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

num_players = 0
for player in players:
    num_players += 1

# -> refactor
num_players = len(players)

 

5. Упростите условное выражение до оператора return

Когда мы достигаем конца метода и хотим вернуть True или False , обычно это делается так. Если условие истинно, мы возвращаем True. В противном случае мы возвращаем False в конце. Однако лучше просто вернуть результат напрямую:

def function():
    if isinstance(a, b) or issubclass(b, a):
        return True
    return False

# -> refactor
def function():
    return isinstance(a, b) or issubclass(b, a)

Одна вещь, о которой мы должны знать, это то, что это можно сделать только в том случае, если выражение оценивается как логическое. Обе функции isinstance() и issubclass() возвращают логическое значение, так что это нормально. Но в следующем примере первое выражение pythonistas — это список, а не логическое значение.

Если pythonistas является действительным непустым списком, это вернет список вместо ожидаемого логического значения, а затем потенциально может быть ошибкой в ​​​​вашем приложении. Итак, чтобы убедиться, что мы возвращаем здесь логическое значение, мы можем обернуть возврат в вызов функции bool() .

def any_pythonistas():
    pythonistas = [coder for coder in coders if is_good_in_python(coder)]
    if pythonistas or self.is_pythonista():
        return True
    return False

# -> refactor
def any_hats():
    pythonistas = [coder for coder in coders if is_good_in_python(coder)]
    return bool(pythonistas or self.is_pythonista())

 

6. Объединить повторяющиеся блоки в условном

Мы всегда должны искать возможности для удаления повторяющегося кода. Лучше всего это делать там, где есть несколько одинаковых блоков внутри цепочки if…elif .

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

def process_payment(payment, currency):
    if currency == "USD":
        process_standard_payment(payment)
    elif currency == "EUR":
        process_standard_payment(payment)
    else:
        process_international_payment(payment)

# -> refactor
def process_payment(payment, currency):
    if currency == "USD" or currency == "EUR":
        process_standard_payment(payment)
    else:
        process_international_payment(payment)

 

7. Замените несколько сравнений одной и той же переменной оператором in

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

def process_payment(payment, currency):
    if currency == "USD" or currency == "EUR":
        process_standard_payment(payment)
    else:
        process_international_payment(payment)

# -> refactor
def process_payment(payment, currency):
    if currency in ["USD", "EUR"]:
        process_standard_payment(payment)
    else:
        process_international_payment(payment)

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

# -> refactor
def process_payment(payment, currency):
    if currency in {"USD", "EUR"}:
        process_standard_payment(payment)
    else:
        process_international_payment(payment)

 

8. Замените yield внутри цикла for на yield from

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

Если у вас есть итерируемый список, вместо того, чтобы говорить  for item in iterable: yield item , вы можете просто сказать  yield from iterable.  Это короче и устраняет ручной цикл по итерации, что также может привести к повышению производительности.

def get_content(entry):
    for block in entry.get_blocks():
        yield block

# -> refactor
def get_content(entry):
    yield from entry.get_blocks()

 

Бонус: бесплатное расширение для рефакторинга VS Code/PyCharm:

Существует расширение для VS Code и PyCharm, которое поможет вам идентифицировать эти шаблоны рефакторинга. Это расширение Sourcery. Sourcery — это бесплатное расширение, которое вы можете легко установить и которое затем даст вам полезные советы по рефакторингу. Вы можете установить и протестировать его здесь: Sourcery.ai 




0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest
0 комментариев
Межтекстовые Отзывы
Посмотреть все комментарии