Python
SimpleNamespace в Python: пример для настроек
SimpleNamespace из модуля types позволяет создать простой объект с полями и обращаться к ним через точку: settings.debug, settings.timeout, settings.host. Это удобно для небольших настроек, тестовых данных и сценариев, где класс писать не хочется, а словарь выглядит шумно
SimpleNamespace не заменяет полноценные модели данных. Он не проверяет типы, не валидирует значения и не защищает от случайных новых полей. Зато он прост, читается легко и хорошо подходит для маленьких конфигов
По этой теме полезно отдельно посмотреть Составьте еженедельное расписание занятий, чтобы расширить контекст и сравнить подходы
По этой теме полезно отдельно посмотреть Аннотации типов для декораторов в Python, чтобы расширить контекст и сравнить подходы
Минимальный пример
from types import SimpleNamespace
settings = SimpleNamespace(
host='localhost',
port=8000,
debug=True,
)
print(settings.host)
print(settings.port)
print(settings.debug)
Результат:
localhost
8000
True
В словаре пришлось бы писать settings['host']. В SimpleNamespace можно писать settings.host, как у обычного объекта
Настройки для скрипта
Представим небольшой скрипт, который делает запросы к API
from types import SimpleNamespace
config = SimpleNamespace(
base_url='https://api.example.com',
timeout=15,
retries=3,
debug=False,
)
print(f'API: {config.base_url}')
print(f'Timeout: {config.timeout}')
Такой объект удобно передавать в функции
def print_config(config):
mode = 'debug' if config.debug else 'production'
print(f'Режим: {mode}')
print(f'Повторов: {config.retries}')
print_config(config)
Если настроек мало и они не требуют строгой проверки, SimpleNamespace делает код короче
Создать SimpleNamespace из словаря
Часто настройки приходят как словарь. Его можно распаковать через **
from types import SimpleNamespace
data = {
'host': 'localhost',
'port': 8000,
'debug': True,
}
settings = SimpleNamespace(**data)
print(settings.host)
print(settings.port)
Это удобно после чтения JSON, простого конфига или тестовых данных
Но есть важное ограничение: ключи словаря должны быть подходящими именами атрибутов
data = {
'api-token': 'secret',
}
К такому полю нельзя нормально обратиться как settings.api-token. Для таких данных лучше оставить словарь или заранее нормализовать ключи
Обновить поле
Поля можно менять после создания
settings = SimpleNamespace(debug=False, retries=3)
settings.debug = True
settings.retries = 5
print(settings)
Результат будет похож на:
namespace(debug=True, retries=5)
Можно добавить новое поле:
settings.timeout = 30
Это удобно, но одновременно опасно. Если случайно написать settings.timout = 30 с ошибкой в имени, Python просто создаст новое поле. Он не скажет, что вы хотели изменить timeout
SimpleNamespace и словарь
Словарь лучше, если ключи приходят извне, могут содержать любые строки или часто перебираются в цикле
settings = {
'host': 'localhost',
'port': 8000,
}
for key, value in settings.items():
print(key, value)
SimpleNamespace лучше, если набор полей маленький и вы хотите обращаться к ним как к атрибутам
settings = SimpleNamespace(host='localhost', port=8000)
print(settings.host)
Практическое правило: если данные похожи на произвольную таблицу ключей, берите dict. Если данные похожи на маленький объект настроек, можно взять SimpleNamespace
SimpleNamespace и dataclass
dataclass лучше, если нужна структура посерьезнее: понятные поля, значения по умолчанию, подсказки типов, методы, сравнение объектов
from dataclasses import dataclass
@dataclass
class Settings:
host: str
port: int = 8000
debug: bool = False
settings = Settings(host='localhost')
SimpleNamespace проще, но слабее. Он не описывает структуру явно
from types import SimpleNamespace
settings = SimpleNamespace(host='localhost', port=8000, debug=False)
Если проект растет и настройки становятся важной частью приложения, лучше перейти на dataclass, Pydantic или другой инструмент конфигурации
Значения по умолчанию
Можно сделать маленькую функцию, которая собирает настройки с defaults
from types import SimpleNamespace
def make_settings(**overrides):
defaults = {
'host': 'localhost',
'port': 8000,
'timeout': 15,
'debug': False,
}
defaults.update(overrides)
return SimpleNamespace(**defaults)
settings = make_settings(debug=True, timeout=30)
print(settings.debug)
print(settings.timeout)
Так удобно в небольших скриптах и тестах, где не хочется заводить отдельный класс
Где использовать SimpleNamespace
Маленькие настройки скрипта
Тестовые данные в unit-тестах
Результат функции с несколькими именованными полями
Прототипы, где структура еще может меняться
Учебные примеры, где словарь отвлекает от основной идеи
Где не использовать
Сложная бизнес-модель
Данные, приходящие от пользователя без проверки
Большой конфиг приложения
Объекты, где важны типы и валидация
Публичный API библиотеки, который будут использовать другие разработчики
Частые ошибки
Ожидать, что SimpleNamespace проверит типы
Случайно создать новое поле из-за опечатки
Передавать в SimpleNamespace(**data) словарь с неподходящими ключами
Использовать его там, где нужен dataclass
Смешивать доступ через точку и словарный доступ. settings.host работает, а settings['host'] уже нет
Практические задачи
Создайте настройки для API-клиента: base_url, timeout, retries
Соберите SimpleNamespace из словаря через **data
Напишите функцию make_settings(), которая добавляет значения по умолчанию
Сравните один и тот же конфиг в виде словаря, SimpleNamespace и dataclass
Проверьте, что произойдет при опечатке в имени поля
SimpleNamespace — это простой способ сделать объект с полями без объявления класса. Он хорош для маленьких настроек, тестовых данных и прототипов
Если нужны строгие типы, валидация, предсказуемая структура и защита от ошибок, лучше использовать dataclass, Pydantic или обычный класс. Если ключи динамические и приходят извне, часто удобнее оставить словарь