Как писать чистый код на Python

Python — один из наиболее элегантных и чистых языков программирования. Но красивый и чистый синтаксис не означает чистый код. И не избавляет разработчиков от необходимости изучать наилучшие приемы и шаблоны проектирования.

Что такое чистый код?

Процитируем Бьерна Страуструпа, создателя языка C++. Он дал очень четкое определение того, что можно считать чистым кодом.

«Я хочу, чтобы мой код был красивым и эффективным. Логика должна быть понятной — так багам будет сложнее спрятаться. Зависимостей должно быть как можно меньше — это облегчает поддержку. Обработка ошибок должна выполняться согласно определенной стратегии. А производительность должна быть приближена к оптимальной — чтобы не соблазнять людей заняться непринципиальными оптимизациями, которые могли бы запутать код. Чистый код делает что-то одно, и делает это хорошо».

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

  • Сфокусированность. Каждая функция, класс или модуль выполняют какую-то одну задачу, причем хорошо.
  • Читабельность. Как сказал Грэйди Буч, автор книги «Object-Oriented Analysis and Design with Applications», чистый код читается, как хорошо написанная проза.
  • Легкость отладки.
  • Легкость поддержки. Если код чистый, другие разработчики без проблем смогут его читать и улучшать.
  • Высокая производительность.

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

В этой статье мы рассмотрим несколько советов, как писать чистый код на Python.

Чистый код на Python

Имена

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

Несколько примеров:

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

# Не рекомендуется
# Переменная au - это число активных пользователей
au = 105

# Рекомендуется
total_active_users = 105

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

# Не рекомендуется
c = [“UK”, “USA”, “UAE”]

for x in c:
print(x)

# Рекомендуется
cities = [“UK”, “USA”, “UAE”]
    for city in cities:
        print(city)

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

# Не рекомендуется
fn = 'John'
Ln = ‘Doe’
cre_tmstp = 1621535852

# Рекомендуется
first_name = ‘JOhn’
Las_name = ‘Doe’
creation_timestamp = 1621535852

Используйте один и тот же набор слов. Непоследовательность будет путать читателя. Это касается не только имен переменных, файлов, функций, но даже и структуры директорий.

# Не рекомендуется
client_first_name = ‘John’
customer_last_name = ‘Doe;

# Рекомендуется
client_first_name = ‘John’
client_last_name = ‘Doe’

# Также обратите внимание на следующий пример:
# Не рекомендуется
def fetch_clients(response, variable):
    # do something
    pass

def fetch_posts(res, var):
    # do something
    pass

# Рекомендуется
def fetch_clients(response, variable):
    # do something
    pass

def fetch_posts(response, variable):
    # do something
    pass

Начните отслеживать проблемы (issues) в кодовой базе в своем редакторе.

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

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

Конечно, вы можете использовать различные инструменты для отслеживания технического долга, но лучше начать пользоваться соответствующими расширениями для редактора кода. Самые популярные из них также интегрируются с Jira, Linear, Asana и другими инструментами для управления проектами.

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

import random

# Не рекомендуется
def roll_dice():
    return random.randint(0, 4)  # what is 4 supposed to represent?

# Рекомендуется
DICE_SIDES = 4

def roll_dice():
    return random.randint(0, DICE_SIDES)

Функции

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

# Не рекомендуется
def get_users(): 
    # do something
    Pass

def fetch_user(id): 
    # do something
    Pass

def get_posts(): 
    # do something
    Pass

def fetch_post(id):
    # do something
    pass

# Рекомендуется
def fetch_users(): 
    # do something
    Pass

def fetch_user(id): 
    # do something
    Pass

def fetch_posts(): 
    # do something
    Pass

def fetch_post(id):
    # do something
    pass

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

# Не рекомендуется
def fetch_and_display_users():
users = [] # result from some api call

    for user in users:
        print(user)


# Рекомендуется
def fetch_usersl():
    users = [] # result from some api call
        return users

def display_users(users):
for user in users:
        print(user)

Не используйте Boolean flags. Это переменные, содержащие булевы значения — True или False. Они передаются в функцию для определения ее поведения.

text = "Python is a simple and elegant programming language."

# Не рекомендуется
def transform_text(text, uppercase):
    if uppercase:
        return text.upper()
    else:
        return text.lower()

uppercase_text = transform_text(text, True)
lowercase_text = transform_text(text, False)


# Рекомендуется
def transform_to_uppercase(text):
    return text.upper()

def transform_to_lowercase(text):
    return text.lower()

uppercase_text = transform_to_uppercase(text)
lowercase_text = transform_to_lowercase(text)

Классы

Не добавляйте лишний контекст. Например, не следует добавлять ненужные слова к именам переменных.

# Не рекомендуется
class Person:
    def __init__(self, person_username, person_email, person_phone, person_address):
        self.person_username = person_username
        self.person_email = person_email
        self.person_phone = person_phone
        self.person_address = person_address

# Рекомендуется
class Person:
    def __init__(self, username, email, phone, address):

        self.username = username
        self.email = email
        self.phone = phone
        self.address = address

В этом примере мы находимся внутри класса Person, поэтому нет нужды добавлять префикс person_ к каждой переменной класса.

Бонус: модульность кода

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

От редакции Pythonist. О модулях можно почитать в статье «Как импортировать в Python?».

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

Заключение

Чистый код дает много преимуществ. Здесь и улучшение качества ПО, и легкая поддержка, и уменьшение технического долга.

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

Перевод статьи «10 must-know patterns for writing clean code with Python».