python-configuration
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChinesePython 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 environmentpython
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 environmentFundamental 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 failure mid-request.
None必需的配置应立即导致应用崩溃并给出清晰的错误信息。
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)启动时的清晰错误比请求过程中出现的值导致的神秘故障要好得多。
NonePattern 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 file for local development (never commit this):
.envbash
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"}为本地开发创建一个文件(切勿提交此文件):
.envbash
undefined.env (add to .gitignore)
.env (add to .gitignore)
DB_PASSWORD=local_dev_password
API_SECRET_KEY=dev-secret-key
DEBUG=true
undefinedDB_PASSWORD=local_dev_password
API_SECRET_KEY=dev-secret-key
DEBUG=true
undefinedPattern 4: Namespaced Environment Variables
模式4:命名空间环境变量
Prefix related variables for clarity and easy debugging.
bash
undefined为相关变量添加前缀,以提高清晰度并便于调试。
bash
undefinedDatabase 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 vUsage:
bash
ALLOWED_HOSTS=example.com,api.example.com,localhost
MAX_CONNECTIONS=50
DEBUG=truePydantic会自动处理常见的转换操作。
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=truePattern 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.LOCALUsage
Usage
if settings.is_production:
configure_production_logging()
else:
configure_debug_logging()
undefinedif settings.is_production:
configure_production_logging()
else:
configure_debug_logging()
undefinedPattern 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:6379Pattern 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 if the env var isn't set.
/run/secrets/db_password对于容器环境,从挂载的文件中读取密钥。
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_passwordPattern 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 selfBest Practices Summary
最佳实践总结
- Never hardcode config - All environment-specific values from env vars
- Use typed settings - Pydantic-settings with validation
- Fail fast - Crash on missing required config at startup
- Provide dev defaults - Make local development easy
- Never commit secrets - Use files (gitignored) or secret managers
.env - Namespace variables - ,
DB_HOSTfor clarityREDIS_URL - Import settings singleton - Don't call throughout code
os.getenv() - Document all variables - README should list required env vars
- Validate early - Check config correctness at boot time
- Use secrets_dir - Support mounted secrets in containers
- 切勿硬编码配置 - 所有环境特定的值均来自环境变量
- 使用类型化设置 - 带验证功能的Pydantic-settings
- 快速失败 - 启动时若缺失必需配置则立即崩溃
- 提供开发环境默认值 - 简化本地开发流程
- 切勿提交密钥 - 使用文件(已加入.gitignore)或密钥管理工具
.env - 为变量添加命名空间 - 使用、
DB_HOST以提高清晰度REDIS_URL - 导入设置单例 - 不要在代码各处调用
os.getenv() - 记录所有变量 - README应列出必需的环境变量
- 尽早验证 - 在启动时检查配置的正确性
- 使用secrets_dir - 支持容器中的挂载密钥