← Назад к вопросам

Как определить константу в Python?

1.3 Junior🔥 61 комментариев
#Soft Skills

Комментарии (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) обеспечивает хороший уровень безопасности на практике.