ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Python] python-decouple 라이브러리
    언어/파이썬 & 장고 2026. 4. 12. 21:45

    프로젝트별 설정을 동적으로 처리하기 위한 설정 파일 및 환경 변수 관리 라이브러리입니다. 코드와 설정의 엄격한 분리(Strict separation of config from code)를 목표로 합니다.


    1. 개요

    python-decouple은 애플리케이션 코드에서 설정값(Configuration)을 분리하여 관리하기 위한 Python 라이브러리입니다.

    원래 Django 프로젝트를 위해 만들어졌으나, 현재는 모든 Python 프로젝트에서 범용적으로 사용할 수 있는 독립 라이브러리로 발전하였습니다. 핵심 철학은 12-Factor App 방법론의 "Config" 원칙, 즉 코드와 설정은 반드시 분리되어야 한다는 것에 기반합니다.


    2. 라이브러리 기능 설명

    2-1. config() 함수 — 핵심 인터페이스

    설정값을 읽어오는 주요 함수입니다.

    from decouple import config
    
    SECRET_KEY = config('SECRET_KEY')                          # 필수값 (없으면 에러)
    DEBUG      = config('DEBUG', default=False, cast=bool)    # 기본값 + 타입 캐스팅
    EMAIL_PORT = config('EMAIL_PORT', default=25, cast=int)   # 정수 타입
    인자 설명
    key 환경 변수 또는 설정 파일의 키 이름
    default 값이 없을 때 사용할 기본값
    cast 문자열을 특정 타입으로 변환하는 callable

    2-2. 설정 소스 및 우선순위

    decouple은 다음 순서로 설정값을 탐색합니다 (위일수록 우선순위 높음):

    1. 환경 변수 (os.environ) — 가장 높은 우선순위 (v3.0부터 Unix 방식 적용)
    2. 설정 파일 (.env 또는 .ini 파일)
    3. config() 호출 시 지정한 default

    2-3. 지원 파일 형식

    .env 파일 (단순 key=value 형식)

    DEBUG=True
    SECRET_KEY=my-very-secret-key
    DATABASE_URL=mysql://user:pass@localhost/mydb
    ALLOWED_HOSTS=.localhost,.herokuapp.com

    .ini 파일 (ConfigParser 형식)

    [settings]
    DEBUG=True
    SECRET_KEY=my-very-secret-key
    TEMPLATE_DEBUG=%(DEBUG)s

    2-4. 타입 캐스팅 (Type Casting)

    설정 파일에서 읽은 값은 기본적으로 문자열(str)이므로, cast 파라미터로 변환이 필요합니다.

    # os.environ['DEBUG'] = 'False' 일 때
    config('DEBUG', cast=bool)   # → False (올바른 변환)
    
    # 주의: bool('False') == True (Python 내장 변환은 잘못된 결과)
    # decouple의 cast=bool은 'false', '0', 'no' 등을 False로 처리합니다.
    
    config('PORT', cast=int)                            # → 정수
    config('RATE', cast=float)                          # → 실수
    config('HOSTS', cast=lambda v: v.split(','))        # → 커스텀 변환

    2-5. Csv() 헬퍼 — 리스트 설정 파싱

    쉼표로 구분된 문자열을 리스트로 변환합니다.

    from decouple import config, Csv
    
    # .env: ALLOWED_HOSTS=.localhost,.herokuapp.com
    config('ALLOWED_HOSTS', cast=Csv())
    # → ['.localhost', '.herokuapp.com']
    
    # 정수 리스트
    # .env: LIST_OF_INTS=1,2,3,4,5
    config('LIST_OF_INTS', cast=Csv(int))
    # → [1, 2, 3, 4, 5]
    
    # 튜플로 변환
    config('SECURE_PROXY_SSL_HEADER', cast=Csv(post_process=tuple))
    # → ('HTTP_X_FORWARDED_PROTO', 'https')
    
    # 커스텀 구분자 및 스트립
    csv = Csv(cast=lambda s: s.upper(), delimiter='\t', strip=' %*')

    Csv() 주요 옵션:

    옵션 설명
    cast 각 요소에 적용할 타입 변환
    delimiter 구분자 (기본값: ,)
    strip 각 요소에서 제거할 문자
    post_process 최종 결과에 적용할 callable (예: tuple)

    2-6. Choices() 헬퍼 — 허용값 검증

    설정값이 허용된 선택지 중 하나인지 검증합니다. 유효하지 않은 값이면 ValueError를 발생시킵니다.

    from decouple import config, Choices
    
    # .env: CONNECTION_TYPE=usb
    config('CONNECTION_TYPE', cast=Choices(['eth', 'usb', 'bluetooth']))
    # → 'usb' (정상)
    
    # .env: CONNECTION_TYPE=serial
    config('CONNECTION_TYPE', cast=Choices(['eth', 'usb', 'bluetooth']))
    # → ValueError: serial is not a valid choice. (오류)
    
    # 타입 캐스팅과 함께 사용
    config('LEVEL', cast=Choices([7, 14, 42], cast=int))
    
    # Django 스타일 튜플
    config('STATUS', cast=Choices([('active', 'Active'), ('inactive', 'Inactive')]))

    2-7. AutoConfig — 자동 설정 파일 탐색

    config는 내부적으로 AutoConfig를 사용하여 현재 모듈 디렉터리부터 재귀적으로 상위 디렉터리를 탐색하며 .env 또는 settings.ini 파일을 자동으로 찾습니다.

    from decouple import config  # AutoConfig가 자동으로 파일 탐색

    2-8. 커스텀 파일 경로 지정

    특정 경로의 .env 파일을 직접 지정할 수 있습니다.

    from decouple import Config, RepositoryEnv
    import os
    
    DOTENV_FILE = os.environ.get("DOTENV_FILE", ".env")
    config = Config(RepositoryEnv(DOTENV_FILE))
    
    SECRET_KEY = config('SECRET_KEY')

    2-9. Fail-Fast 정책

    기본값 없이 선언된 설정 키가 없으면 즉시 UndefinedValueError를 발생시켜 설정 누락으로 인한 런타임 오류를 조기에 발견할 수 있습니다.

    # .env에 SECRET_KEY가 없을 경우
    SECRET_KEY = config('SECRET_KEY')
    # → UndefinedValueError: SECRET_KEY not found.

    3. 사용 예시

    3-1. Django 프로젝트 설정 예시

    # settings.py
    from decouple import config, Csv
    from dj_database_url import parse as db_url
    
    SECRET_KEY = config('SECRET_KEY')
    DEBUG = config('DEBUG', default=False, cast=bool)
    ALLOWED_HOSTS = config('ALLOWED_HOSTS', default='localhost', cast=Csv())
    
    DATABASES = {
        'default': config('DATABASE_URL', cast=db_url)
    }
    
    EMAIL_HOST = config('EMAIL_HOST', default='localhost')
    EMAIL_PORT = config('EMAIL_PORT', default=25, cast=int)
    EMAIL_HOST_USER = config('EMAIL_HOST_USER', default='')
    EMAIL_HOST_PASSWORD = config('EMAIL_HOST_PASSWORD', default='')
    EMAIL_USE_TLS = config('EMAIL_USE_TLS', default=True, cast=bool)
    # .env
    SECRET_KEY=django-insecure-your-secret-key-here
    DEBUG=False
    ALLOWED_HOSTS=.myapp.com,.herokuapp.com
    DATABASE_URL=postgres://user:pass@localhost/mydb
    EMAIL_HOST=smtp.gmail.com
    EMAIL_PORT=587
    EMAIL_HOST_USER=myapp@gmail.com
    EMAIL_HOST_PASSWORD=app-specific-password
    EMAIL_USE_TLS=True

    3-2. FastAPI / 일반 Python 프로젝트 예시

    # config.py
    from decouple import config
    
    APP_HOST = config('APP_HOST', default='0.0.0.0')
    APP_PORT = config('APP_PORT', default=8000, cast=int)
    DATABASE_URL = config('DATABASE_URL')
    REDIS_URL = config('REDIS_URL', default='redis://localhost:6379')
    LOG_LEVEL = config('LOG_LEVEL', default='INFO')

    3-3. 환경별(dev/staging/prod) 설정 분리 예시

    # config.py
    import os
    from decouple import Config, RepositoryEnv
    
    ENV = os.environ.get('APP_ENV', 'development')
    env_files = {
        'development': '.env.dev',
        'staging': '.env.staging',
        'production': '.env.prod',
    }
    config = Config(RepositoryEnv(env_files[ENV]))
    
    DATABASE_URL = config('DATABASE_URL')
    DEBUG = config('DEBUG', cast=bool)

    4. 언제 쓰고 왜 좋은지

    4-1. 언제 사용하면 좋은가?

    • 민감한 정보(API 키, DB 비밀번호, 시크릿 키 등)를 코드에 하드코딩하지 않아야 할 때
    • 개발(dev) / 스테이징(staging) / 운영(prod) 환경마다 다른 설정값이 필요할 때
    • Docker, Heroku, AWS 등 환경 변수 기반 배포 환경을 사용할 때
    • 팀 협업 시 각자의 로컬 환경 설정을 독립적으로 유지해야 할 때
    • 12-Factor App 방법론을 따르는 프로젝트를 구성할 때

    4-2. 왜 좋은가?

    보안 강화

    설정값을 코드 외부로 분리하므로 .gitignore.env를 추가하면 민감 정보가 버전 관리 시스템에 노출되지 않습니다.

    타입 안전성

    cast=bool 사용 시 "False" 문자열을 올바르게 False로 변환합니다. Python 내장 bool("False")는 비어있지 않은 문자열이므로 True를 반환하는 함정을 피할 수 있습니다.

    # 위험한 방법 (잘못된 결과)
    import os
    debug = bool(os.environ.get('DEBUG', 'False'))  # → True (버그!)
    
    # 안전한 방법
    from decouple import config
    debug = config('DEBUG', default=False, cast=bool)  # → False (올바름)

    다중 소스 지원

    환경 변수, .env 파일, .ini 파일을 우선순위에 따라 자동으로 탐색하므로 배포 환경에 맞는 설정을 유연하게 적용할 수 있습니다.

    Fail-Fast로 설정 누락 조기 발견

    앱 시작 시점에 필수 설정값 누락을 즉시 감지하여, 운영 환경에서 설정 오류로 인한 예기치 않은 장애를 방지합니다.

    재배포 없이 설정 변경 가능

    환경 변수나 설정 파일만 변경하면 코드 수정·재배포 없이 동작 방식을 제어할 수 있습니다.


    5. 같이 쓰면 좋은 라이브러리

    5-1. dj-database-url

    데이터베이스 URL 문자열을 Django의 DATABASES 설정 딕셔너리로 파싱해주는 라이브러리입니다. python-decouple과 함께 사용하면 DB 접속 정보를 간결하게 관리할 수 있습니다.

    from decouple import config
    from dj_database_url import parse as db_url
    
    DATABASES = {
        'default': config('DATABASE_URL', cast=db_url)
    }
    # .env
    DATABASE_URL=postgres://user:password@localhost:5432/mydb

    5-2. python-dotenv

    .env 파일을 로드하는 가장 기본적인 라이브러리입니다. python-decouple의 하위 기능과 겹치지만, 특정 프레임워크(예: FastAPI의 BaseSettings)와 함께 사용할 때 .env 파일 로딩 용도로 활용할 수 있습니다.

    비교 항목 python-decouple python-dotenv
    타입 캐스팅 지원 (cast) 미지원
    .ini 파일 지원 지원 미지원
    값 검증 (Choices) 지원 미지원
    학습 곡선 약간 있음 매우 낮음

    5-3. pydantic-settings (Pydantic v2)

    Pydantic 기반의 설정 관리 라이브러리로, 타입 힌트와 유효성 검사를 활용한 강력한 설정 클래스를 제공합니다. FastAPI 프로젝트에서 주로 사용됩니다.

    from pydantic_settings import BaseSettings
    
    class Settings(BaseSettings):
        database_url: str
        debug: bool = False
        allowed_hosts: list[str] = []
    
        class Config:
            env_file = ".env"
    
    settings = Settings()

    python-decouple과 비교하면 더 강력한 타입 검증과 IDE 자동완성을 지원하지만, Pydantic 의존성이 추가됩니다.

    5-4. environs

    marshmallow를 기반으로 한 환경 변수 파싱 라이브러리입니다. URL, 이메일, UUID 등 복잡한 타입 파싱을 지원합니다.

    from environs import Env
    
    env = Env()
    env.read_env()
    
    DEBUG = env.bool("DEBUG")
    PORT = env.int("PORT", 8000)
    DATABASE_URL = env.url("DATABASE_URL")

    6. 결론

    python-decouple은 코드와 설정의 분리라는 단순하지만 중요한 원칙을 실용적으로 구현한 라이브러리입니다.

    핵심 장점 요약:

    • .env / .ini / 환경 변수를 우선순위에 따라 자동 탐색합니다.
    • cast 파라미터로 타입 변환을 안전하게 처리합니다.
    • Csv(), Choices() 헬퍼로 리스트 파싱 및 값 검증을 지원합니다.
    • Fail-Fast 정책으로 설정 누락을 앱 시작 시점에 즉시 감지합니다.
    • Django, FastAPI, Flask 등 모든 Python 프로젝트에서 사용할 수 있습니다.

    복잡한 설정 관리가 필요하다면 pydantic-settings를, 단순하고 직관적인 설정 분리가 필요하다면 python-decouple이 최적의 선택입니다. 특히 Django 프로젝트에서 dj-database-url과 함께 사용하면 배포 환경에 따른 설정 관리를 매우 간결하게 처리할 수 있습니다.

    Pydantic을 사용 중이거나 FastAPI 기반이라면 python-decouple을 추가로 설치할 필요가 없습니다. pydantic-settings가 훨씬 상위 호환입니다.

    댓글