How can I access environment variables in Python?
Environment variables in Python can be accessed primarily using the os module’s environ attribute or the getenv() function. The os.environ provides a dictionary-like interface to access environment variables directly, while os.getenv() offers a safer way to retrieve variables with default values when they don’t exist.
Contents
- Basic Methods for Accessing Environment Variables
- Using os.environ
- Using os.getenv()
- Best Practices and Safety Considerations
- Alternative Libraries
- Common Use Cases
Basic Methods for Accessing Environment Variables
Python provides several built-in ways to access environment variables, with the most common being through the os module. The primary methods include:
os.environ- A mapping object representing the string environmentos.getenv()- A function to get environment variables with default valuesos.environ.get()- Dictionary-style access with default values
These methods allow you to retrieve system-wide configuration, API keys, database credentials, and other sensitive information that shouldn’t be hard-coded in your applications.
Using os.environ
The os.environ object behaves like a dictionary, providing direct access to environment variables:
import os
# Access an environment variable
api_key = os.environ['API_KEY']
# Check if an environment variable exists
if 'DATABASE_URL' in os.environ:
db_url = os.environ['DATABASE_URL']
# Iterate through all environment variables
for key, value in os.environ.items():
print(f"{key}: {value}")
Key characteristics of os.environ:
- Raises a
KeyErrorif the variable doesn’t exist (when using bracket notation) - Returns
Noneif the variable exists but is empty - Automatically converts values to strings
Important: Using bracket notation (
os.environ['VARIABLE']) will raise aKeyErrorif the environment variable doesn’t exist. Use this method only when you’re certain the variable must exist.
Using os.getenv()
The os.getenv() function provides a safer way to access environment variables by allowing you to specify a default value:
import os
# Get with default value if not exists
api_key = os.getenv('API_KEY', 'default-key-here')
debug_mode = os.getenv('DEBUG', 'False')
# Check if variable exists without raising an error
if os.getenv('API_KEY') is not None:
print("API key is configured")
# Get boolean values
is_production = os.getenv('ENVIRONMENT') == 'production'
Advantages of os.getenv():
- Never raises a
KeyError - Allows specifying default values
- More flexible for optional configuration
- Better for handling missing variables gracefully
Best Practices and Safety Considerations
When working with environment variables in Python, follow these best practices:
1. Always provide default values for optional variables:
# Good
timeout = os.getenv('REQUEST_TIMEOUT', '30')
# Bad (potential KeyError)
timeout = os.environ['REQUEST_TIMEOUT']
2. Validate environment variables before use:
def get_database_config():
db_url = os.getenv('DATABASE_URL')
if not db_url:
raise ValueError("DATABASE_URL must be set")
return db_url
3. Use type conversion when needed:
# Convert string values to appropriate types
max_connections = int(os.getenv('MAX_CONNECTIONS', '10'))
enable_feature = os.getenv('ENABLE_FEATURE', 'False').lower() == 'true'
4. Handle sensitive information securely:
- Never log environment variables containing secrets
- Use
.envfiles for local development (withpython-dotenv) - Consider using secret management services in production
5. Check for existence before critical operations:
if os.getenv('API_KEY') and os.getenv('DATABASE_URL'):
# Proceed with application startup
pass
else:
# Handle missing configuration
sys.exit("Missing required environment variables")
Alternative Libraries
While the os module is built-in, several third-party libraries provide enhanced functionality:
1. python-dotenv for local development:
# Load .env file
from dotenv import load_dotenv
load_dotenv()
# Now access variables as usual
api_key = os.getenv('API_KEY')
2. pydantic-settings for type-safe configuration:
from pydantic import BaseSettings
class Settings(BaseSettings):
api_key: str
debug: bool = False
settings = Settings()
3. dynaconf for multiple environment support:
from dynaconf import Dynaconf
settings = Dynaconf(
environments=True,
settings_files=['.secrets.toml', '.env']
)
Common Use Cases
Application Configuration:
import os
class Config:
DEBUG = os.getenv('DEBUG', 'False') == 'True'
TESTING = os.getenv('TESTING', 'False') == 'True'
SECRET_KEY = os.getenv('SECRET_KEY', 'dev-key-insecure')
# Database configuration
DATABASE_URL = os.getenv('DATABASE_URL', 'sqlite:///app.db')
# API configuration
API_BASE_URL = os.getenv('API_BASE_URL', 'https://api.example.com')
API_TIMEOUT = int(os.getenv('API_TIMEOUT', '30'))
Feature Flags:
import os
def is_feature_enabled(feature_name):
return os.getenv(f'ENABLE_{feature_name.upper()}', 'False').lower() == 'true'
# Usage
if is_feature_enabled('new_dashboard'):
show_new_dashboard()
Environment-Specific Behavior:
import os
ENVIRONMENT = os.getenv('ENVIRONMENT', 'development')
if ENVIRONMENT == 'production':
# Production-specific code
pass
elif ENVIRONMENT == 'testing':
# Testing-specific code
pass
else:
# Development default
pass
File Paths:
import os
# Get user-specific directories
home_dir = os.getenv('HOME', os.getenv('USERPROFILE'))
config_dir = os.getenv('XDG_CONFIG_HOME', os.path.join(home_dir, '.config'))
# Build paths
app_config_path = os.path.join(config_dir, 'myapp', 'config.json')
Conclusion
Accessing environment variables in Python is straightforward using the built-in os module. The key takeaways are:
- Use
os.getenv()for safer access with default values instead ofos.environ[]to avoid KeyError exceptions - Always provide sensible defaults for optional environment variables
- Validate and convert environment variables to appropriate data types
- Consider using third-party libraries like
python-dotenvfor local development - Never hard-code sensitive information or use environment variables inappropriately
Environment variables are essential for building portable, secure, and configurable applications. By following these practices, you can effectively manage configuration across different deployment environments while keeping sensitive data out of your source code.