Featured image of post [Python Cheatsheet] 16. Environment Variables - os.environ/dotenv 패턴

[Python Cheatsheet] 16. Environment Variables - os.environ/dotenv 패턴

환경 변수를 안전하게 다루기 위한 치트시트입니다. os.environ 읽기/쓰기, python-dotenv로 .env 파일 로드, 설정 분리 패턴, 보안 주의점과 12-factor app 원칙을 최소 예제로 정리합니다.

환경 변수는 코드와 설정을 분리하는 핵심 방법입니다. 이 치트시트는 os.environ으로 환경 변수 읽기/쓰기, python-dotenv로 .env 파일 관리, 보안 주의점을 정리합니다.

언제 이 치트시트를 보나?

  • API 키, DB 연결 문자열 등 민감한 정보를 코드에서 분리하고 싶을 때
  • 개발/스테이징/프로덕션 환경별 설정을 다르게 하고 싶을 때

핵심 패턴

  • 읽기: os.environ.get("KEY", "default") → 없으면 기본값 반환
  • 필수 값: os.environ["KEY"] → 없으면 KeyError (의도적 실패)
  • .env 파일: python-dotenv로 로드 → 개발 환경에서 편리
  • 절대 커밋 금지: .env.gitignore에 추가

최소 예제

1
2
3
4
5
6
7
8
import os

# 환경 변수 읽기 (기본값 지정)
db_host = os.environ.get("DB_HOST", "localhost")
db_port = int(os.environ.get("DB_PORT", "5432"))
debug = os.environ.get("DEBUG", "false").lower() == "true"

print(f"Connecting to {db_host}:{db_port}, debug={debug}")
1
2
3
4
# 환경 변수 필수 값 (없으면 바로 에러)
import os

api_key = os.environ["API_KEY"]  # KeyError if not set
1
2
3
4
5
# 환경 변수 쓰기 (현재 프로세스에서만 유효)
import os

os.environ["MY_VAR"] = "value"
print(os.environ.get("MY_VAR"))  # "value"
1
2
3
4
5
# 모든 환경 변수 확인
import os

for key, value in os.environ.items():
    print(f"{key}={value}")

python-dotenv 사용

1
2
# 설치
pip install python-dotenv
1
2
3
4
5
6
# .env 파일 예시 (프로젝트 루트에 생성)
DB_HOST=localhost
DB_PORT=5432
DB_NAME=myapp
API_KEY=your-secret-key-here
DEBUG=true
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# .env 파일 로드
from dotenv import load_dotenv
import os

# .env 파일에서 환경 변수 로드
load_dotenv()  # 기본: 현재 디렉토리의 .env

# 이제 os.environ으로 접근 가능
api_key = os.environ.get("API_KEY")
debug = os.environ.get("DEBUG", "false").lower() == "true"
1
2
3
4
5
6
# 특정 경로의 .env 파일 로드
from dotenv import load_dotenv
from pathlib import Path

env_path = Path(__file__).parent / ".env.local"
load_dotenv(dotenv_path=env_path)
1
2
3
4
5
# .env 파일 내용을 dict로 가져오기 (os.environ에 로드하지 않음)
from dotenv import dotenv_values

config = dotenv_values(".env")
print(config["DB_HOST"])

설정 클래스 패턴 (권장)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import os
from dataclasses import dataclass
from dotenv import load_dotenv

load_dotenv()

@dataclass
class Config:
    db_host: str = os.environ.get("DB_HOST", "localhost")
    db_port: int = int(os.environ.get("DB_PORT", "5432"))
    db_name: str = os.environ.get("DB_NAME", "myapp")
    api_key: str = os.environ.get("API_KEY", "")
    debug: bool = os.environ.get("DEBUG", "false").lower() == "true"

config = Config()
print(config.db_host, config.debug)

.gitignore 설정

1
2
3
4
5
6
# .gitignore에 반드시 추가
.env
.env.local
.env.*.local
*.pem
*.key

자주 하는 실수/주의점

  • .env 파일 커밋 금지: API 키, 비밀번호가 Git 히스토리에 남으면 보안 사고
  • 타입 변환 필수: 환경 변수는 항상 문자열로 반환됨 → int(), bool() 직접 변환
    1
    2
    3
    4
    5
    
    # 숫자
    port = int(os.environ.get("PORT", "8080"))
    
    # 불리언 (주의: "false"도 truthy)
    debug = os.environ.get("DEBUG", "false").lower() in ("true", "1", "yes")
    
  • 로드 순서: load_dotenv()는 기존 환경 변수를 덮어쓰지 않음 → 시스템 환경 변수가 우선
  • 프로덕션에서는 .env 사용 자제: Docker/K8s에서는 시스템 환경 변수나 시크릿 매니저 사용
  • .env.example 제공: 필요한 환경 변수 목록을 팀원에게 공유 (값은 비움)

.env.example 템플릿

1
2
3
4
5
6
7
8
# .env.example (커밋 가능)
# 이 파일을 .env로 복사하고 실제 값을 채우세요

DB_HOST=localhost
DB_PORT=5432
DB_NAME=
API_KEY=
DEBUG=false

관련 링크(공식 문서)