← Блог · · Команда ConvertCaseHQ · 6 мин чтения

Именование в Python по PEP 8: snake_case для переменных и функций

PEP 8 требует, чтобы имена функций и переменных были строчными, а слова разделялись подчёркиваниями там, где это нужно для читаемости. Это и есть snake_case: total_price, send_invoice(). Классы пишутся в CapWords (InvoiceSender), константы — заглавными буквами с подчёркиваниями (MAX_RETRIES), а модули получают короткие имена целиком строчными буквами. Этого хватает для большей части кода на Python, который вы будете писать.

Самые полезные подробности — в остальной части раздела PEP 8 об именовании: что значат подчёркивания в начале и в конце имени, как обращаться с аббревиатурами, каких одиночных букв избегать и когда нарушить правила — верное решение. Всё ниже сверено с самим PEP 8, а английские фразы в кавычках — собственные слова PEP 8 (перевод дан в скобках).

Соглашения PEP 8 об именовании: коротко

Что вы называетеСтиль по PEP 8Пример
МодульКороткое имя целиком строчными; подчёркивания, если они помогаютbilling.py, tax_rules.py
ПакетКороткое имя целиком строчными; подчёркивания не рекомендуютсяpayments
КлассCapWordsInvoiceSender
ИсключениеCapWords, с окончанием Error, если это ошибкаPaymentDeclinedError
Функция, методsnake_casesend_invoice()
Переменная, переменная экземпляраsnake_casetotal_price
Первый аргумент методаself или cls для методов классаdef from_settings(cls, settings)
КонстантаЗаглавные буквы с подчёркиваниями, обычно на уровне модуляMAX_RETRIES
Переменная типаКороткое имя в CapWordsT, AnyStr
Непубличное имяОдно подчёркивание в начале_rate_cache

Вот большая часть таблицы в одном небольшом модуле:

# billing.py
MAX_RETRIES = 3
_rate_cache = {}


class PaymentDeclinedError(Exception):
    pass


class InvoiceSender:
    def __init__(self, smtp_host):
        self.smtp_host = smtp_host
        self._attempts = 0

    def send_invoice(self, invoice_id):
        self._attempts += 1
        ...

    @classmethod
    def from_settings(cls, settings):
        return cls(settings["smtp_host"])

Стоит знать ещё две более редкие строки. Переменные типа могут получать суффикс _co или _contra, обозначающий ковариантность или контравариантность, как в VT_co = TypeVar('VT_co', covariant=True). А глобальные переменные следуют правилам для функций; если модуль предназначен для использования через from module import *, PEP 8 рекомендует перечислить его публичные имена в __all__.

Зачем вообще нужен snake_case?

PEP 8 появился в июле 2001 года, а в числе его авторов указаны Guido van Rossum, Barry Warsaw и Alyssa Coghlan. Отправная точка — одно из наблюдений Guido: код читают гораздо чаще, чем пишут. Правила именования служат этой цели. Подчёркивания сохраняют видимыми границы слов даже в длинных именах (days_since_last_login), а разделение на значения в snake_case и классы в CapWords подсказывает, что за вещь перед вами, ещё до того, как вы посмотрите её определение. Для публичных API PEP 8 устанавливает и главный принцип: имена должны отражать то, как вещь используется, а не то, как она реализована.

Что значат подчёркивания

В Python нет ключевого слова private, поэтому эту работу по соглашению выполняют подчёркивания. PEP 8 выделяет четыре формы:

  • _single_leading: слабый сигнал «internal use» (для внутреннего использования). from module import * такие имена пропускает, но больше ничто не мешает ими пользоваться.
  • single_trailing_: помогает избежать конфликта с ключевым словом. class_ лучше, чем clss, хотя PEP 8 замечает, что синоним может оказаться ещё лучше.
  • __double_leading: внутри класса запускает искажение имён (name mangling). PEP 8 советует применять его только для того, чтобы избежать конфликтов с атрибутами в подклассах, и признаёт, что некоторым оно не нравится.
  • __double_leading_and_trailing__: имена «magic» (магические), такие как __init__ и __file__. PEP 8 говорит никогда не придумывать их самим; используйте только документированные.

Искажение имён удивляет тех, кто принимает его за приватность. Это переименование, а не замок:

class Account:
    def __init__(self):
        self.__pin = "1234"

acct = Account()
acct.__pin            # AttributeError
acct._Account__pin    # "1234": the mangled name still works

Константы — это соглашение, а не правило

Запись имени заглавными буквами не мешает его переприсвоить; Python без возражений выполнит MAX_RETRIES = 4. Если вы хотите, чтобы это проверял инструмент, пометьте имя аннотацией typing.Final:

from typing import Final

MAX_RETRIES: Final = 3
MAX_RETRIES = 4  # still runs, but mypy reports:
                 # Cannot assign to final name "MAX_RETRIES"

Члены перечислений (enum) — ещё одно место, где встречаются заглавные буквы. Руководство enum HOWTO в документации Python настоятельно рекомендует имена членов в UPPER_CASE: отчасти потому, что перечисления представляют константы, отчасти чтобы избежать конфликтов с именами методов; пример — class Color(Enum) с членами RED и GREEN.

Аббревиатуры, одиночные буквы и другие особые случаи

Аббревиатуры в именах классов

PEP 8 говорит писать в CapWords каждую букву аббревиатуры заглавной, поэтому HTTPServerError лучше, чем HttpServerError. Стандартная библиотека следует этому в таких местах, как http.server.HTTPServer и json.JSONDecodeError. В snake_case аббревиатуры просто пишутся строчными: parse_json, http_status.

Это важно, если вы переименовываете с помощью инструмента. Наш конвертер регистра превращает processOrder в process_order, а HTTPServerError — в http_server_error, и для snake_case это в точности то, что нужно. Но в PascalCase он пишет аббревиатуры как слова, так что из HTTP server error получается HttpServerError, и заглавные буквы вам придётся исправить вручную, чтобы привести имя в соответствие с PEP 8.

Буквы, которых стоит избегать

Никогда не используйте l (строчная L), O (заглавная o) и I (заглавная i) как односимвольные имена. В некоторых шрифтах их невозможно отличить от 1 и 0.

mixedCase

Имена функций в camelCase допустимы только там, где этот стиль уже преобладает, ради обратной совместимости. Собственный пример PEP 8 — модуль threading.

Почему стандартная библиотека нарушает собственные правила

PEP 8 признаёт, что именование в библиотеке Python — «a bit of a mess» (довольно беспорядочное). Вам встретятся logging.getLogger() и assertEqual() из unittest в mixedCase, а также классы со строчной буквы вроде datetime.datetime. Встроенные типы вроде list и dict написаны строчными намеренно: PEP 8 описывает отдельное соглашение для встроенных объектов, где CapWords используется только для имён исключений и встроенных констант.

Два положения из PEP 8 объясняют, почему эти имена в основном остаются как есть. Во-первых, если у существующей библиотеки другой стиль, предпочтение отдаётся внутреннему единообразию. Во-вторых, раздел под названием «A Foolish Consistency is the Hobgoblin of Little Minds» (глупая последовательность — пугало для мелких умов): единообразие с PEP 8 важно, единообразие внутри проекта важнее, а внутри модуля или функции — важнее всего. Не ломайте обратную совместимость только ради соблюдения правил. Поэтому тестовый класс unittest по-прежнему определяет setUp(): фреймворк вызывает именно это имя.

Проверяйте имена автоматически с помощью Ruff или pep8-naming

Просматривать имена глазами не нужно. Их проверяет плагин flake8 pep8-naming, а Ruff реализует те же проверки в виде правил N. Возьмём такой файл:

maxRetries = 3


class order_processor:
    def processOrder(self, orderId):
        totalPrice = 0
        return totalPrice


class InvalidOrder(Exception):
    pass

Ruff отмечает в нём каждое имя:

$ ruff check --select N --output-format concise orders.py
orders.py:1:1: N816 Variable `maxRetries` in global scope should not be mixedCase
orders.py:4:7: N801 Class name `order_processor` should use CapWords convention
orders.py:5:9: N802 Function name `processOrder` should be lowercase
orders.py:5:28: N803 Argument name `orderId` should be lowercase
orders.py:6:9: N806 Variable `totalPrice` in function should be lowercase
orders.py:10:7: N818 Exception name `InvalidOrder` should be named with an Error suffix
Found 6 errors.

Чтобы включить эти правила для всего проекта, добавьте их в pyproject.toml:

[tool.ruff.lint]
extend-select = ["N"]

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

Чек-лист по именованию в PEP 8

  • snake_case — для функций, методов, переменных и аргументов.
  • CapWords — для классов, с аббревиатурами заглавными буквами и суффиксом Error у исключений.
  • Заглавные буквы с подчёркиваниями — для констант уровня модуля, плюс Final, если вы хотите, чтобы их проверял инструмент.
  • Короткие имена модулей строчными; в именах пакетов избегайте подчёркиваний.
  • Одно подчёркивание в начале — для внутренних имён; двойное — только чтобы избежать конфликтов в подклассах.
  • Если существующая библиотека использует другой стиль, подстраивайтесь под библиотеку.

Переходите с языка на язык? Наша шпаргалка для разработчиков сопоставляет правила Python с JavaScript, Java, Go, Rust и другими языками.