Именование модулей Python: рекомендации и варианты
Соглашения об именовании модулей Python
Какое соглашение об именовании модулей является наиболее распространённым и рекомендуемым?
Основное правило, описанное в PEP 8, предписывает использовать для модулей имена в стиле snake_case - все буквы строчные, слова разделяются символом подчёркивания. Это обеспечивает единообразие, читаемость и избегает путаницы с именами классов (CamelCase) и констант (UPPER_CASE).
# имя модуля: my_module.py
# содержимое: def my_function(): passPython module naming (соглашения об именовании модулей python)
Цель: соответствие стандартным библиотекам Python (os, json, datetime) и упрощение импорта. Используется для любых модулей: утилит, вспомогательных функций, конфигураций.
Типичные ошибки: использование заглавных букв (MyModule.py) или дефисов (my-module.py) - Python не разрешает импорт модулей с дефисом, так как это недопустимый синтаксис. Решение: всегда заменять дефис на подчёркивание.
Как назвать модуль, состоящий из одного слова?
Если имя модуля короткое и однозначное, допустимо использовать одно слово без подчёркиваний. Примеры: utils.py, config.py, models.py. Это подходит для часто используемых модулей с широкой областью. Однако стоит избегать совпадений с именами встроенных модулей (math, sys).
# config.py
DATABASE_URL = 'sqlite:///test.db'Python modules (модули python)
Проблема: конфликт имён с модулями из стандартной библиотеки. Например, создание файла string.py перекроет стандартный модуль string. Решение: проверять имя на уникальность, использовать префикс, например app_config.py.
Когда стоит использовать префикс с подчёркиванием для модуля?
Модули, предназначенные только для внутреннего использования внутри пакета, принято начинать с одного подчёркивания: _internal.py. Это сигнал разработчикам, что модуль не является частью публичного API.
# пакет mypackage/
# __init__.py
# _helpers.py (внутренний)Python module main (основной модуль __main__)
Цель: скрыть вспомогательные функции от пользователей пакета. При импорте from mypackage import * такие модули не попадают в область видимости (если не задан __all__).
Ошибка: попытка импортировать модуль с подчёркиванием как публичный - возможно, но считается нарушением соглашения. Решение: явно экспортировать только нужные имена через __all__.
Как быть с модулями, содержащими цифры?
Цифры в именах модулей допустимы, но только если они несут смысловую нагрузку (например, версия: v2_api.py). Не рекомендуется начинать имя с цифры (2api.py - синтаксическая ошибка).
# v2_schema.py
Проблема: цифры в начале имени файла недопустимы в Python. Решение: всегда ставить цифры в середине или конце, или использовать буквенный префикс.
Какое имя выбрать для модуля с тестовыми функциями?
Для тестов принято добавлять суффикс _test или префикс test_. Например, test_math_utils.py или math_utils_test.py. Это позволяет инструментам (pytest, unittest) автоматически находить тесты.
# test_calculator.py
import pytest
from calculator import add
def test_add(): ...
Цель: соответствие стандартам тестовых фреймворков. Используется в проектах с тестированием.
Ошибка: нерегулярные имена, не соответствующие шаблону test_*.py - pytest может их пропустить. Решение: придерживаться шаблона, заданного в конфигурации pytest.
Выбор соглашения об именовании модулей зависит от контекста, но основным остаётся snake_case с учётом уникальности и читаемости.
Расширенные примеры именования модулей Python
Ниже приведены подробные примеры, демонстрирующие различные соглашения и их практическое применение.
Пример 1: Базовый модуль в стиле snake_case
# file: data_processing.py
def clean_data(data):
return [x.strip() for x in data if x]
def transform_data(data):
return [x.upper() for x in data]
# Импорт: >>> import data_processing >>> dp.clean_data([' a ', 'b ', ' c']) ['a', 'b', 'c']
Пример 2: Модуль с одним словом и конфликт имён
# file: json.py (плохо! перекрывает стандартный json)
def custom_load(data):
return {'custom': data}
# другой файл:
import json # теперь это локальный модуль, а не стандартный
print(json.custom_load('test'))
# Ошибка: AttributeError: module 'json' has no attribute 'loads' # Решение: переименовать модуль в my_json.py или json_utils.py
Пример 3: Внутренний модуль с подчёркиванием
# пакет mypackage/
# __init__.py
from ._helpers import internal_func
__all__ = ['public_func']
# _helpers.py
def internal_func():
return "internal"
# другой код:
import mypackage
print(mypackage.internal_func()) # работает, но не рекомендуется
print(mypackage.__all__) # ['public_func']
# При from mypackage import * внутренний модуль не импортируется автоматически.
Пример 4: Тестовый модуль с префиксом test_
# file: test_math_ops.py
import pytest
from math_ops import add, divide
def test_add():
assert add(2, 3) == 5
def test_divide():
with pytest.raises(ZeroDivisionError):
divide(5, 0)
# Запуск pytest: $ pytest test_math_ops.py -v ============================= test session starts ============================== test_math_ops.py::test_add PASSED test_math_ops.py::test_divide PASSED
Пример 5: Модули с цифрами в имени
# file: api_v2.py
VERSION = 2
def process_request(data):
return {'version': VERSION, 'data': data}
# Неправильно: 2api.py (синтаксическая ошибка при импорте)
>>> import api_v2
>>> api_v2.process_request('test')
{'version': 2, 'data': 'test'}
Пример 6: Пакет с несколькими модулями (структура)
# дерево:
my_package/
__init__.py
core.py
utils/
__init__.py
file_io.py
_config.py
# __init__.py (my_package)
from .core import main_func
from .utils.file_io import read_file
# utils/file_io.py
def read_file(path):
with open(path, 'r') as f:
return f.read()
# utils/_config.py (внутренний)
import os
DEFAULT_PATH = os.getcwd()
# Импорт:
>>> from my_package import main_func, read_file
>>> read_file('test.txt')
'...'
# _config не импортируется через from my_package import *
Эти примеры показывают типичные случаи применения соглашений и предостерегают от распространённых ошибок.