Переменные окружения в Python: os.environ и dotenv (практическое руководство)
Переменные окружения помогают отделить конфигурацию от кода: вы не хардкодите пароли и ключи API, а читаете их из окружения. В Python для этого есть словарь os.environ, а для удобной локальной разработки — библиотека python-dotenv, читающая значения из файла .env.
Что такое переменные окружения и зачем они нужны
os.environ: чтение, запись, удаление
os.environ — это отображение (похоже на словарь), которое содержит переменные окружения текущего процесса.
import os
# Чтение: безопасно с умолчанием
home = os.environ.get("HOME", "")
print("HOME:", home)
# Жёсткое чтение (поднимет KeyError, если нет переменной)
# path = os.environ["PATH"]
# Установка переменной для текущего процесса (и дочерних)
os.environ["API_TOKEN"] = "secret-123"
print("API_TOKEN set:", os.environ.get("API_TOKEN"))
# Удаление переменной (если отсутствует — KeyError)
if "API_TOKEN" in os.environ:
del os.environ["API_TOKEN"]
os.putenv vs os.environ
os.putenv существует для совместимости с низкоуровневым API ОС, но в большинстве случаев достаточно работы с os.environ. Изменения в os.environ автоматически отражаются в окружении дочерних процессов.
Безопасные паттерны чтения конфигурации
Заведите небольшие утилиты для обязательных и необязательных переменных с преобразованием типов.
import os
class ConfigError(RuntimeError):
pass
def get_required(name: str) -> str:
value = os.environ.get(name)
if value is None or value == "":
raise ConfigError(f"Отсутствует обязательная переменная окружения: {name}")
return value
def get_int(name: str, default: int) -> int:
raw = os.environ.get(name)
if raw is None:
return default
try:
return int(raw)
except ValueError:
raise ConfigError(f"Переменная {name} должна быть целым числом (получено: {raw!r})")
def get_bool(name: str, default: bool) -> bool:
raw = os.environ.get(name)
if raw is None:
return default
return raw.strip().lower() in {"1", "true", "yes", "y", "on"}
.env и библиотека python-dotenv
Для локальной разработки удобно хранить значения в файле .env и подгружать их при старте приложения.
# Установка
pip install python-dotenv
Пример файла .env (не коммитьте его в репозиторий):
# .env
API_TOKEN=secret-123
DB_URL=postgresql+psycopg://user:pass@localhost:5432/app
DEBUG=true
PORT=8080
# Комментарии начинаются с #
Загрузка значений в окружение:
import os
from dotenv import load_dotenv, find_dotenv
# Ищет .env, поднимаясь по дереву каталогов, и загружает его
load_dotenv(find_dotenv())
print("API_TOKEN:", os.getenv("API_TOKEN"))
По умолчанию load_dotenv не перезаписывает уже существующие переменные. Для явного перекрытия используйте override=True.
load_dotenv(find_dotenv(), override=True)
Несколько файлов .env
Вы можете явно загрузить нужный файл:
from dotenv import load_dotenv
load_dotenv(".env.production")
Мини‑проект: конфигурация через окружение
Соберём простой модуль конфигурации, который валидирует обязательные значения и приводит типы.
# config.py
import os
from dotenv import load_dotenv, find_dotenv
load_dotenv(find_dotenv()) # безопасно для локалки
class ConfigError(RuntimeError):
pass
def _required(name: str) -> str:
value = os.environ.get(name)
if not value:
raise ConfigError(f"Отсутствует {name}. Задайте её в окружении или .env")
return value
def _to_bool(value: str, default: bool=False) -> bool:
if value is None:
return default
return value.strip().lower() in {"1", "true", "yes", "y", "on"}
def _to_int(value: str, default: int) -> int:
if value is None:
return default
try:
return int(value)
except ValueError as e:
raise ConfigError(f"Ожидалось целое число, получено: {value!r}") from e
API_TOKEN = _required("API_TOKEN")
DB_URL = _required("DB_URL")
DEBUG = _to_bool(os.environ.get("DEBUG"), default=False)
PORT = _to_int(os.environ.get("PORT"), default=8000)
# main.py
from config import API_TOKEN, DB_URL, DEBUG, PORT
def run():
print("Config loaded:n",
f"API_TOKEN=**** (len={len(API_TOKEN)})n",
f"DB_URL={DB_URL}n",
f"DEBUG={DEBUG}n",
f"PORT={PORT}")
if __name__ == "__main__":
run()
Запуск с передачей переменных на лету:
# Linux/macOS (bash/zsh)
API_TOKEN=xxx DB_URL=sqlite:///db.sqlite3 python main.py
# Windows PowerShell
$env:API_TOKEN="xxx"; $env:DB_URL="sqlite:///db.sqlite3"; python .main.py
# Windows CMD
set API_TOKEN=xxx && set DB_URL=sqlite:///db.sqlite3 && python main.py
Советы и типичные ошибки
os.environ["KEY"] без проверки — ловите KeyError. Предпочтительнее os.getenv или обёртки.FAQ коротко
Как задать переменную только для одного запуска?
# Linux/macOS
DEBUG=1 python app.py
Как проверить, установлена ли переменная?
import os
if os.getenv("API_TOKEN"):
print("Токен задан")
else:
print("Токен отсутствует")
Почему моих переменных из .env не видно? Убедитесь, что вызвали load_dotenv до чтения переменных и что путь к .env корректный (используйте find_dotenv()).
Куда двигаться дальше
Хотите системно освоить Python с нуля, научиться работать с файловой системой, сетью, тестами и деплоем? Рекомендую пройти практический курс: Освоить Python с нуля и довести навыки до уровня «Гуру» — присоединиться к курсу.
Итоги
Переменные окружения — фундаментальный инструмент конфигурации в Python. Используйте os.environ и python-dotenv для удобной разработки, валидируйте обязательные параметры, храните секреты вне репозитория и не забывайте про безопасность в логах. Такой подход упрощает переносимость, снижает риски и помогает быстро масштабировать приложение между средами.






