python-configuration

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Python Configuration Management

Python配置管理

Externalize configuration from code using environment variables and typed settings. Well-managed configuration enables the same code to run in any environment without modification.
使用环境变量和类型化设置将配置从代码中分离出来。管理得当的配置可让同一代码无需修改即可在任何环境中运行。

When to Use This Skill

何时使用此技能

  • Setting up a new project's configuration system
  • Migrating from hardcoded values to environment variables
  • Implementing pydantic-settings for typed configuration
  • Managing secrets and sensitive values
  • Creating environment-specific settings (dev/staging/prod)
  • Validating configuration at application startup
  • 为新项目搭建配置系统
  • 从硬编码值迁移到环境变量
  • 实现pydantic-settings以进行类型化配置
  • 管理密钥和敏感值
  • 创建环境特定的设置(开发/预发布/生产)
  • 在应用启动时验证配置

Core Concepts

核心概念

1. Externalized Configuration

1. 配置外部化

All environment-specific values (URLs, secrets, feature flags) come from environment variables, not code.
所有环境特定的值(URL、密钥、功能开关)均来自环境变量,而非代码。

2. Typed Settings

2. 类型化设置

Parse and validate configuration into typed objects at startup, not scattered throughout code.
在启动时将配置解析并验证为类型化对象,而非分散在代码各处。

3. Fail Fast

3. 快速失败

Validate all required configuration at application boot. Missing config should crash immediately with a clear message.
在应用启动时验证所有必需的配置。缺失的配置应立即崩溃并给出清晰的提示信息。

4. Sensible Defaults

4. 合理默认值

Provide reasonable defaults for local development while requiring explicit values for sensitive settings.
为本地开发提供合理的默认值,同时要求敏感设置使用显式值。

Quick Start

快速开始

python
from pydantic_settings import BaseSettings
from pydantic import Field

class Settings(BaseSettings):
    database_url: str = Field(alias="DATABASE_URL")
    api_key: str = Field(alias="API_KEY")
    debug: bool = Field(default=False, alias="DEBUG")

settings = Settings()  # Loads from environment
python
from pydantic_settings import BaseSettings
from pydantic import Field

class Settings(BaseSettings):
    database_url: str = Field(alias="DATABASE_URL")
    api_key: str = Field(alias="API_KEY")
    debug: bool = Field(default=False, alias="DEBUG")

settings = Settings()  # Loads from environment

Fundamental Patterns

基础模式

Pattern 1: Typed Settings with Pydantic

模式1:使用Pydantic实现类型化设置

Create a central settings class that loads and validates all configuration.
python
from pydantic_settings import BaseSettings
from pydantic import Field, PostgresDsn, ValidationError
import sys

class Settings(BaseSettings):
    """Application configuration loaded from environment variables."""

    # Database
    db_host: str = Field(alias="DB_HOST")
    db_port: int = Field(default=5432, alias="DB_PORT")
    db_name: str = Field(alias="DB_NAME")
    db_user: str = Field(alias="DB_USER")
    db_password: str = Field(alias="DB_PASSWORD")

    # Redis
    redis_url: str = Field(default="redis://localhost:6379", alias="REDIS_URL")

    # API Keys
    api_secret_key: str = Field(alias="API_SECRET_KEY")

    # Feature flags
    enable_new_feature: bool = Field(default=False, alias="ENABLE_NEW_FEATURE")

    model_config = {
        "env_file": ".env",
        "env_file_encoding": "utf-8",
    }
创建一个中心设置类,用于加载和验证所有配置。
python
from pydantic_settings import BaseSettings
from pydantic import Field, PostgresDsn, ValidationError
import sys

class Settings(BaseSettings):
    """Application configuration loaded from environment variables."""

    # Database
    db_host: str = Field(alias="DB_HOST")
    db_port: int = Field(default=5432, alias="DB_PORT")
    db_name: str = Field(alias="DB_NAME")
    db_user: str = Field(alias="DB_USER")
    db_password: str = Field(alias="DB_PASSWORD")

    # Redis
    redis_url: str = Field(default="redis://localhost:6379", alias="REDIS_URL")

    # API Keys
    api_secret_key: str = Field(alias="API_SECRET_KEY")

    # Feature flags
    enable_new_feature: bool = Field(default=False, alias="ENABLE_NEW_FEATURE")

    model_config = {
        "env_file": ".env",
        "env_file_encoding": "utf-8",
    }

Create singleton instance at module load

Create singleton instance at module load

try: settings = Settings() except ValidationError as e: print(f"Configuration error:\n{e}") sys.exit(1)

Import `settings` throughout your application:

```python
from myapp.config import settings

def get_database_connection():
    return connect(
        host=settings.db_host,
        port=settings.db_port,
        database=settings.db_name,
    )
try: settings = Settings() except ValidationError as e: print(f"Configuration error:\n{e}") sys.exit(1)

在整个应用中导入`settings`:

```python
from myapp.config import settings

def get_database_connection():
    return connect(
        host=settings.db_host,
        port=settings.db_port,
        database=settings.db_name,
    )

Pattern 2: Fail Fast on Missing Configuration

模式2:缺失配置时快速失败

Required settings should crash the application immediately with a clear error.
python
from pydantic_settings import BaseSettings
from pydantic import Field, ValidationError
import sys

class Settings(BaseSettings):
    # Required - no default means it must be set
    api_key: str = Field(alias="API_KEY")
    database_url: str = Field(alias="DATABASE_URL")

    # Optional with defaults
    log_level: str = Field(default="INFO", alias="LOG_LEVEL")

try:
    settings = Settings()
except ValidationError as e:
    print("=" * 60)
    print("CONFIGURATION ERROR")
    print("=" * 60)
    for error in e.errors():
        field = error["loc"][0]
        print(f"  - {field}: {error['msg']}")
    print("\nPlease set the required environment variables.")
    sys.exit(1)
A clear error at startup is better than a cryptic
None
failure mid-request.
必需的配置应立即导致应用崩溃并给出清晰的错误信息。
python
from pydantic_settings import BaseSettings
from pydantic import Field, ValidationError
import sys

class Settings(BaseSettings):
    # Required - no default means it must be set
    api_key: str = Field(alias="API_KEY")
    database_url: str = Field(alias="DATABASE_URL")

    # Optional with defaults
    log_level: str = Field(default="INFO", alias="LOG_LEVEL")

try:
    settings = Settings()
except ValidationError as e:
    print("=" * 60)
    print("CONFIGURATION ERROR")
    print("=" * 60)
    for error in e.errors():
        field = error["loc"][0]
        print(f"  - {field}: {error['msg']}")
    print("\nPlease set the required environment variables.")
    sys.exit(1)
启动时的清晰错误比请求过程中出现的
None
值导致的神秘故障要好得多。

Pattern 3: Local Development Defaults

模式3:本地开发默认值

Provide sensible defaults for local development while requiring explicit values for secrets.
python
class Settings(BaseSettings):
    # Has local default, but prod will override
    db_host: str = Field(default="localhost", alias="DB_HOST")
    db_port: int = Field(default=5432, alias="DB_PORT")

    # Always required - no default for secrets
    db_password: str = Field(alias="DB_PASSWORD")
    api_secret_key: str = Field(alias="API_SECRET_KEY")

    # Development convenience
    debug: bool = Field(default=False, alias="DEBUG")

    model_config = {"env_file": ".env"}
Create a
.env
file for local development (never commit this):
bash
undefined
为本地开发提供合理的默认值,同时要求敏感设置使用显式值。
python
class Settings(BaseSettings):
    # Has local default, but prod will override
    db_host: str = Field(default="localhost", alias="DB_HOST")
    db_port: int = Field(default=5432, alias="DB_PORT")

    # Always required - no default for secrets
    db_password: str = Field(alias="DB_PASSWORD")
    api_secret_key: str = Field(alias="API_SECRET_KEY")

    # Development convenience
    debug: bool = Field(default=False, alias="DEBUG")

    model_config = {"env_file": ".env"}
为本地开发创建一个
.env
文件(切勿提交此文件):
bash
undefined

.env (add to .gitignore)

.env (add to .gitignore)

DB_PASSWORD=local_dev_password API_SECRET_KEY=dev-secret-key DEBUG=true
undefined
DB_PASSWORD=local_dev_password API_SECRET_KEY=dev-secret-key DEBUG=true
undefined

Pattern 4: Namespaced Environment Variables

模式4:命名空间环境变量

Prefix related variables for clarity and easy debugging.
bash
undefined
为相关变量添加前缀,以提高清晰度并便于调试。
bash
undefined

Database configuration

Database configuration

DB_HOST=localhost DB_PORT=5432 DB_NAME=myapp DB_USER=admin DB_PASSWORD=secret
DB_HOST=localhost DB_PORT=5432 DB_NAME=myapp DB_USER=admin DB_PASSWORD=secret

Redis configuration

Redis configuration

REDIS_URL=redis://localhost:6379 REDIS_MAX_CONNECTIONS=10
REDIS_URL=redis://localhost:6379 REDIS_MAX_CONNECTIONS=10

Authentication

Authentication

AUTH_SECRET_KEY=your-secret-key AUTH_TOKEN_EXPIRY_SECONDS=3600 AUTH_ALGORITHM=HS256
AUTH_SECRET_KEY=your-secret-key AUTH_TOKEN_EXPIRY_SECONDS=3600 AUTH_ALGORITHM=HS256

Feature flags

Feature flags

FEATURE_NEW_CHECKOUT=true FEATURE_BETA_UI=false

Makes `env | grep DB_` useful for debugging.
FEATURE_NEW_CHECKOUT=true FEATURE_BETA_UI=false

这样`env | grep DB_`命令在调试时会很有用。

Advanced Patterns

高级模式

Pattern 5: Type Coercion

模式5:类型转换

Pydantic handles common conversions automatically.
python
from pydantic_settings import BaseSettings
from pydantic import Field, field_validator

class Settings(BaseSettings):
    # Automatically converts "true", "1", "yes" to True
    debug: bool = False

    # Automatically converts string to int
    max_connections: int = 100

    # Parse comma-separated string to list
    allowed_hosts: list[str] = Field(default_factory=list)

    @field_validator("allowed_hosts", mode="before")
    @classmethod
    def parse_allowed_hosts(cls, v: str | list[str]) -> list[str]:
        if isinstance(v, str):
            return [host.strip() for host in v.split(",") if host.strip()]
        return v
Usage:
bash
ALLOWED_HOSTS=example.com,api.example.com,localhost
MAX_CONNECTIONS=50
DEBUG=true
Pydantic会自动处理常见的转换操作。
python
from pydantic_settings import BaseSettings
from pydantic import Field, field_validator

class Settings(BaseSettings):
    # Automatically converts "true", "1", "yes" to True
    debug: bool = False

    # Automatically converts string to int
    max_connections: int = 100

    # Parse comma-separated string to list
    allowed_hosts: list[str] = Field(default_factory=list)

    @field_validator("allowed_hosts", mode="before")
    @classmethod
    def parse_allowed_hosts(cls, v: str | list[str]) -> list[str]:
        if isinstance(v, str):
            return [host.strip() for host in v.split(",") if host.strip()]
        return v
使用方式:
bash
ALLOWED_HOSTS=example.com,api.example.com,localhost
MAX_CONNECTIONS=50
DEBUG=true

Pattern 6: Environment-Specific Configuration

模式6:环境特定配置

Use an environment enum to switch behavior.
python
from enum import Enum
from pydantic_settings import BaseSettings
from pydantic import Field, computed_field

class Environment(str, Enum):
    LOCAL = "local"
    STAGING = "staging"
    PRODUCTION = "production"

class Settings(BaseSettings):
    environment: Environment = Field(
        default=Environment.LOCAL,
        alias="ENVIRONMENT",
    )

    # Settings that vary by environment
    log_level: str = Field(default="DEBUG", alias="LOG_LEVEL")

    @computed_field
    @property
    def is_production(self) -> bool:
        return self.environment == Environment.PRODUCTION

    @computed_field
    @property
    def is_local(self) -> bool:
        return self.environment == Environment.LOCAL
使用环境枚举来切换行为。
python
from enum import Enum
from pydantic_settings import BaseSettings
from pydantic import Field, computed_field

class Environment(str, Enum):
    LOCAL = "local"
    STAGING = "staging"
    PRODUCTION = "production"

class Settings(BaseSettings):
    environment: Environment = Field(
        default=Environment.LOCAL,
        alias="ENVIRONMENT",
    )

    # Settings that vary by environment
    log_level: str = Field(default="DEBUG", alias="LOG_LEVEL")

    @computed_field
    @property
    def is_production(self) -> bool:
        return self.environment == Environment.PRODUCTION

    @computed_field
    @property
    def is_local(self) -> bool:
        return self.environment == Environment.LOCAL

Usage

Usage

if settings.is_production: configure_production_logging() else: configure_debug_logging()
undefined
if settings.is_production: configure_production_logging() else: configure_debug_logging()
undefined

Pattern 7: Nested Configuration Groups

模式7:嵌套配置组

Organize related settings into nested models.
python
from pydantic import BaseModel
from pydantic_settings import BaseSettings

class DatabaseSettings(BaseModel):
    host: str = "localhost"
    port: int = 5432
    name: str
    user: str
    password: str

class RedisSettings(BaseModel):
    url: str = "redis://localhost:6379"
    max_connections: int = 10

class Settings(BaseSettings):
    database: DatabaseSettings
    redis: RedisSettings
    debug: bool = False

    model_config = {
        "env_nested_delimiter": "__",
        "env_file": ".env",
    }
Environment variables use double underscore for nesting:
bash
DATABASE__HOST=db.example.com
DATABASE__PORT=5432
DATABASE__NAME=myapp
DATABASE__USER=admin
DATABASE__PASSWORD=secret
REDIS__URL=redis://redis.example.com:6379
将相关设置组织到嵌套模型中。
python
from pydantic import BaseModel
from pydantic_settings import BaseSettings

class DatabaseSettings(BaseModel):
    host: str = "localhost"
    port: int = 5432
    name: str
    user: str
    password: str

class RedisSettings(BaseModel):
    url: str = "redis://localhost:6379"
    max_connections: int = 10

class Settings(BaseSettings):
    database: DatabaseSettings
    redis: RedisSettings
    debug: bool = False

    model_config = {
        "env_nested_delimiter": "__",
        "env_file": ".env",
    }
环境变量使用双下划线表示嵌套关系:
bash
DATABASE__HOST=db.example.com
DATABASE__PORT=5432
DATABASE__NAME=myapp
DATABASE__USER=admin
DATABASE__PASSWORD=secret
REDIS__URL=redis://redis.example.com:6379

Pattern 8: Secrets from Files

模式8:从文件读取密钥

For container environments, read secrets from mounted files.
python
from pydantic_settings import BaseSettings
from pydantic import Field
from pathlib import Path

class Settings(BaseSettings):
    # Read from environment variable or file
    db_password: str = Field(alias="DB_PASSWORD")

    model_config = {
        "secrets_dir": "/run/secrets",  # Docker secrets location
    }
Pydantic will look for
/run/secrets/db_password
if the env var isn't set.
对于容器环境,从挂载的文件中读取密钥。
python
from pydantic_settings import BaseSettings
from pydantic import Field
from pathlib import Path

class Settings(BaseSettings):
    # Read from environment variable or file
    db_password: str = Field(alias="DB_PASSWORD")

    model_config = {
        "secrets_dir": "/run/secrets",  # Docker secrets location
    }
如果未设置环境变量,Pydantic会查找
/run/secrets/db_password
文件。

Pattern 9: Configuration Validation

模式9:配置验证

Add custom validation for complex requirements.
python
from pydantic_settings import BaseSettings
from pydantic import Field, model_validator

class Settings(BaseSettings):
    db_host: str = Field(alias="DB_HOST")
    db_port: int = Field(alias="DB_PORT")
    read_replica_host: str | None = Field(default=None, alias="READ_REPLICA_HOST")
    read_replica_port: int = Field(default=5432, alias="READ_REPLICA_PORT")

    @model_validator(mode="after")
    def validate_replica_settings(self):
        if self.read_replica_host and self.read_replica_port == self.db_port:
            if self.read_replica_host == self.db_host:
                raise ValueError(
                    "Read replica cannot be the same as primary database"
                )
        return self
为复杂需求添加自定义验证。
python
from pydantic_settings import BaseSettings
from pydantic import Field, model_validator

class Settings(BaseSettings):
    db_host: str = Field(alias="DB_HOST")
    db_port: int = Field(alias="DB_PORT")
    read_replica_host: str | None = Field(default=None, alias="READ_REPLICA_HOST")
    read_replica_port: int = Field(default=5432, alias="READ_REPLICA_PORT")

    @model_validator(mode="after")
    def validate_replica_settings(self):
        if self.read_replica_host and self.read_replica_port == self.db_port:
            if self.read_replica_host == self.db_host:
                raise ValueError(
                    "Read replica cannot be the same as primary database"
                )
        return self

Best Practices Summary

最佳实践总结

  1. Never hardcode config - All environment-specific values from env vars
  2. Use typed settings - Pydantic-settings with validation
  3. Fail fast - Crash on missing required config at startup
  4. Provide dev defaults - Make local development easy
  5. Never commit secrets - Use
    .env
    files (gitignored) or secret managers
  6. Namespace variables -
    DB_HOST
    ,
    REDIS_URL
    for clarity
  7. Import settings singleton - Don't call
    os.getenv()
    throughout code
  8. Document all variables - README should list required env vars
  9. Validate early - Check config correctness at boot time
  10. Use secrets_dir - Support mounted secrets in containers
  1. 切勿硬编码配置 - 所有环境特定的值均来自环境变量
  2. 使用类型化设置 - 带验证功能的Pydantic-settings
  3. 快速失败 - 启动时若缺失必需配置则立即崩溃
  4. 提供开发环境默认值 - 简化本地开发流程
  5. 切勿提交密钥 - 使用
    .env
    文件(已加入.gitignore)或密钥管理工具
  6. 为变量添加命名空间 - 使用
    DB_HOST
    REDIS_URL
    以提高清晰度
  7. 导入设置单例 - 不要在代码各处调用
    os.getenv()
  8. 记录所有变量 - README应列出必需的环境变量
  9. 尽早验证 - 在启动时检查配置的正确性
  10. 使用secrets_dir - 支持容器中的挂载密钥