Python
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax and Data Types
-
Section 3: Collections
-
39: Set Operations: Union, Intersection, Difference
-
Section 4: Control Flow
-
Section 5: Functions
-
Section 6: Turtle Graphics and Early Practice Projects
-
Section 7: Working with Files and I/O
-
Section 8: Regular Expressions
-
Section 9: Object-Oriented Python
-
Section 10: Error Handling
-
Section 11: Modules and Packages
-
Section 12: Iterators, Generators, and Functional Tools
-
Section 13: Decorators and Metaprogramming
-
Section 14: Concurrency and Parallelism
-
Section 15: Working with Dates, Times, and Numbers
-
Section 16: Standard Library Deep Dive I: Data Structures
-
Section 17: Standard Library Deep Dive II: System and Introspection
-
Section 18: Standard Library Deep Dive III: Security and Encoding
-
Section 19: Standard Library Deep Dive IV: Text and Data Utilities
-
Section 20: Networking and Web Basics
-
Section 21: Working with Databases
-
Section 22: Testing and Quality
-
Section 23: Advanced Typing
-
Section 24: Context Managers and Resource Handling
-
Section 25: Text, Unicode, and Binary Data
-
Section 26: More Functional and Iteration Tools
-
Section 27: Data Validation and Configuration
-
Section 28: Working with Images and Media
-
Section 29: Property-Based and Documentation Testing
-
Section 30: Packaging and Deployment
-
Section 31: Performance and Internals
-
Section 32: Design Patterns in Python
-
Section 33: GUI Programming
-
Section 34: Security Basics
-
Section 35: Data Structures and Algorithms
-
Section 36: Practical Projects
-
Section 37: Capstone Projects
-
Section 38: Interview and Algorithm Practice
-
Section 39: Writing Idiomatic Python
104: Environment Variables in Python
Listen, there is one mistake almost every developer makes early in their career: hardcoding a password or an API key directly into their source code. I've done it. You might have done it. The problem is that once you push that code to a public repository like GitHub, that secret is out there forever—even if you delete the line in a later commit, it's still in the git history. It's a nightmare to clean up.
To avoid this, we use environment variables. These are values stored on the operating system itself, outside of your code, which your Python script can "look up" while it's running. Let's build a small script that fetches weather data from a hypothetical API to see how this works in practice.
The mistake we've all made: Hardcoding secrets
If I were just hacking something together quickly, I might be tempted to write something like this:
import requests
def get_weather(city):
# This is the mistake. Never do this in a real project.
api_key = "sk_live_51MzX82LpQz91kLp"
url = f"https://api.weather-service.com/v1/current?q={city}&key={api_key}"
return requests.get(url).json()
print(get_weather("New York"))
It works perfectly! But if I share this script with a teammate or upload it to a server, my private API key goes with it. Now anyone who sees the code can use my paid account. I need to get that string out of my .py file and into the environment.
Moving the secret to the environment
First, I'll set the variable on my machine. If you're on Mac or Linux, you'd run export WEATHER_API_KEY='your_actual_key_here' in your terminal. On Windows, it's set WEATHER_API_KEY='your_actual_key_here'. Now the value lives in the shell's memory, not in my text editor.
Now, I'll use Python's built-in os module to grab it. I'm going to use os.environ, which acts like a dictionary containing all the environment variables available to the process.
import os
import requests
def get_weather(city):
# Now I'm pulling the key from the OS environment
api_key = os.environ["WEATHER_API_KEY"]
url = f"https://api.weather-service.com/v1/current?q={city}&key={api_key}"
return requests.get(url).json()
print(get_weather("New York"))
This is much safer. The code describes how to use the key, but it doesn't actually contain the key.
Dealing with missing keys gracefully
Here's where I ran into a snag while testing this. If I run this script in a new terminal window where I forgot to run the export command, Python throws a KeyError: 'WEATHER_API_KEY' and the whole program crashes. That's a bit too aggressive for a production app.
Instead of using square brackets, I'll switch to os.getenv(). This method is better because if the variable doesn't exist, it returns None (or a default value you provide) instead of crashing your program. It allows me to handle the error politely.
import os
import requests
def get_weather(city):
# .getenv() is safer than os.environ[]
api_key = os.getenv("WEATHER_API_KEY")
if api_key is None:
print("Error: Please set the WEATHER_API_KEY environment variable.")
return None
url = f"https://api.weather-service.com/v1/current?q={city}&key={api_key}"
return requests.get(url).json()
print(get_weather("New York"))
Now, if the key is missing, the user gets a helpful message instead of a wall of traceback text. It's a small change, but it's the difference between a script that feels like a toy and one that feels like professional software.
📋 Practical Task
Exercise: Building a Secure Database Connector
You are building a module that connects to a database. To keep the credentials secure, you must avoid hardcoding them. Create a Python script that does the following:
- Uses
os.getenv()to look for two environment variables:DB_USERandDB_PASSWORD. - If either variable is missing, the script should print a specific error message:
"Missing database credentials. Please check your environment variables."and exit the function. - If both are present, the script should print a fake connection string in this format:
"Connecting to database as [DB_USER] with password [DB_PASSWORD]..."
Testing your code: To test the success path, run export DB_USER=admin and export DB_PASSWORD=secret123 (or the Windows set equivalent) in your terminal before running your script.
There are no comments for now.