Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Определение констант в Python
В Python нет встроенного механизма для создания истинных констант (как в C++ или Java), однако существуют соглашения и подходы для имитации неизменяемости.
Основные подходы
1. Соглашение о названии (UPPER_CASE)
# Самый распространённый способ — константы в UPPER_CASE
MAX_RETRY_ATTEMPTS = 3
DEFAULT_TIMEOUT = 30
API_BASE_URL = "https://api.example.com"
DATABASE_POOL_SIZE = 10
TAX_RATE = 0.15
# Использование
for attempt in range(MAX_RETRY_ATTEMPTS):
try:
result = fetch_data(timeout=DEFAULT_TIMEOUT)
except TimeoutError:
continue
Проблема: это просто соглашение. Python не препятствует изменению:
# Можно случайно изменить
MAX_RETRY_ATTEMPTS = 5 # Ой! Это было не нужно
2. Использование Final из typing (Python 3.8+)
from typing import Final
# Аннотация Final сигнализирует что это константа
MAX_RETRY_ATTEMPTS: Final = 3
DEFAULT_TIMEOUT: Final = 30
API_BASE_URL: Final = "https://api.example.com"
# Type checker (mypy) предупредит об ошибке
MAX_RETRY_ATTEMPTS = 5 # mypy error: Cannot assign to Final
# Но runtime Python это все еще позволит!
MAX_RETRY_ATTEMPTS = 5 # Работает, но mypy жалуется
3. Использование литералов (Literal)
from typing import Literal
# Определяем разрешённые значения
LogLevel = Literal["DEBUG", "INFO", "WARNING", "ERROR"]
Environment = Literal["development", "staging", "production"]
def log_message(level: LogLevel, message: str):
if level not in ["DEBUG", "INFO", "WARNING", "ERROR"]:
raise ValueError(f"Invalid log level: {level}")
print(f"[{level}] {message}")
log_message("INFO", "Application started")
log_message("INVALID", "Test") # mypy error
4. Константы в классах
class Config:
"""Константы конфигурации"""
MAX_RETRY_ATTEMPTS = 3
DEFAULT_TIMEOUT = 30
DEBUG = False
# С type hints
MAX_CONNECTIONS: int = 100
API_KEY: str = "secret-key"
# Использование
Config.MAX_RETRY_ATTEMPTS
Config.DEFAULT_TIMEOUT
# Защита от изменения (по соглашению)
class ImmutableConfig:
MAX_RETRY_ATTEMPTS = 3
def __setattr__(self, name, value):
raise AttributeError("Cannot modify config")
config = ImmutableConfig()
config.MAX_RETRY_ATTEMPTS = 5 # AttributeError: Cannot modify config
5. Использование enum для категориальных данных
from enum import Enum, IntEnum
# Текстовые перечисления
class Environment(Enum):
DEVELOPMENT = "development"
STAGING = "staging"
PRODUCTION = "production"
# Числовые перечисления
class HttpStatus(IntEnum):
OK = 200
CREATED = 201
BAD_REQUEST = 400
UNAUTHORIZED = 401
NOT_FOUND = 404
SERVER_ERROR = 500
# Использование
env = Environment.PRODUCTION
print(env.value) # "production"
status = HttpStatus.OK
print(status.value) # 200
print(status == 200) # True
# Перебор всех значений
for env in Environment:
print(env.name, env.value)
6. Использование dataclass с frozen=True
from dataclasses import dataclass
@dataclass(frozen=True)
class DatabaseConfig:
"""Неизменяемая конфигурация БД"""
host: str
port: int
username: str
password: str
database: str
config = DatabaseConfig(
host="localhost",
port=5432,
username="admin",
password="secret",
database="myapp"
)
# Нельзя изменить
config.host = "newhost" # FrozenInstanceError
# Но можно создать новый с изменениями
from dataclasses import replace
new_config = replace(config, host="newhost")
7. Использование NamedTuple
from typing import NamedTuple
class Point(NamedTuple):
x: int
y: int
# NamedTuple неизменяем
point = Point(10, 20)
# Нельзя изменить
point.x = 30 # AttributeError: cannot assign to field 'x'
# Но можно создать новый
new_point = point._replace(x=30)
8. Использование модульных констант
# constants.py
"""Модуль с глобальными константами"""
# API
API_BASE_URL = "https://api.example.com"
API_TIMEOUT = 30
API_MAX_RETRIES = 3
# Database
DB_HOST = "localhost"
DB_PORT = 5432
DB_POOL_SIZE = 10
# Auth
JWT_SECRET = "secret-key"
JWT_EXPIRATION = 3600
# Application
DEBUG_MODE = False
LOG_LEVEL = "INFO"
# В других файлах
from constants import API_BASE_URL, DB_HOST
9. Использование ConfigParser для внешних констант
import configparser
# config.ini
"""
[api]
base_url = https://api.example.com
timeout = 30
[database]
host = localhost
port = 5432
[logging]
level = INFO
"""
# Чтение конфигурации
config = configparser.ConfigParser()
config.read('config.ini')
api_url = config.get('api', 'base_url')
db_host = config.get('database', 'host')
log_level = config.get('logging', 'level')
10. Использование Pydantic для валидированных констант
from pydantic import BaseModel, Field
class AppConfig(BaseModel):
"""Валидированная конфигурация с типами"""
api_url: str
api_timeout: int = Field(default=30, ge=1, le=300)
db_host: str
db_port: int = Field(default=5432, ge=1, le=65535)
debug: bool = False
class Config:
frozen = True # Неизменяемо
# Загрузить из переменных окружения
config = AppConfig(
api_url="https://api.example.com",
api_timeout=30,
db_host="localhost",
db_port=5432
)
# Использование
print(config.api_url)
config.api_url = "new" # ValidationError: Config is frozen
Сравнение подходов
| Подход | Простота | Безопасность | Type hints | Лучше для |
|---|---|---|---|---|
| UPPER_CASE | Очень просто | Низкая | Нет | Простые скрипты |
| Final | Просто | Средняя (mypy) | Да | Production код |
| Enum | Средне | Высокая | Да | Категориальные значения |
| Frozen dataclass | Средне | Высокая | Да | Конфигурация |
| Module constants | Просто | Средняя | Опционально | Глобальные значения |
| Pydantic | Средне | Высокая | Да | Валидация конфига |
Best Practices
# 1. Используй UPPER_CASE для простых констант
MAX_BATCH_SIZE = 1000
# 2. Добавляй type hints с Final
from typing import Final
MAX_RETRIES: Final[int] = 3
# 3. Группируй связанные константы в классы
class Config:
API_URL = "https://api.example.com"
API_TIMEOUT = 30
API_RETRIES = 3
# 4. Используй Enum для категориальных данных
from enum import Enum
class Environment(Enum):
DEV = "development"
PROD = "production"
# 5. Экспортируй const в отдельном модуле
# constants.py
# __init__.py
# from .constants import *
# 6. Документируй назначение
SEARCH_RESULT_PAGE_SIZE = 20 # Количество результатов на странице
CACHE_TTL_SECONDS = 3600 # Время жизни кэша в секундах
# 7. Используй Pydantic для конфигурации с валидацией
from pydantic import BaseSettings
class Settings(BaseSettings):
api_key: str
db_url: str
Python не имеет истинных констант, но комбинация типизации (Final) и соглашений (UPPER_CASE) обеспечивает хороший уровень безопасности на практике.