Working with environment variables in Python.
Published: 2022-04-30 09:54:42

Often times when developing software, we find the need to read values defined by other pieces of software, or even define these variables ourselves! This article will talk all about that.

## Accessing global environment variables

### Using `os.environ`

We can get and set environment variables using the `os.environ` dictionnary. Getting the value of an environment variable:

```python
>>> import os
>>> os.environ["HOME"]
'/home/username'
```

Setting the value of an environment variable:

```python
>>> import os
>>> os.environ["FOO"] = "bar"
>>> os.environ["FOO"]
'bar'
```

Because `os.environ` is a `mapping` object, we can use `.pop()` to delete a variable from `os.environ`:

```python
>>> import os
>>> os.environ["FOO"] = "bar"
>>> print(os.environ.get("FOO"))
bar
>>> os.environ.pop("FOO")
'bar'
>>> print(os.environ.get("FOO"))
None
```

If the environment variable doesn't exist, Python will raise a `KeyError`, to mitigate this, we can use `os.environ.get()` which returns `None` if the environment variable doesn't exist:

```python
>>> import os
>>> bar = os.environ.get("BAR")
>>> print(bar)
None
```

A neat trick of `os.environ.get()` is **setting default values.** This value will be returned if the variable doesn't exist. We can achieve this by passing the default value as the second parameter of `os.environ.get()`

```python
>>> import os
>>> bar = os.environ.get("BAR")
>>> print(bar)
None
>>> bar = os.environ.get("BAR", "bar")
>>> print(bar)
bar
```

### Using `os.getenv()`

Now you might be wondering: "What is the difference between `os.environ.get()` and `os.getenv()`?", well the answer is simply that **there is no difference.** In terms of performance, both functions perform relatively similarly:

```shell
$ python3 -m timeit -s "import os" "os.environ.get('HOME')"
500000 loops, best of 5: 730 nsec per loop
$  python3 -m timeit -s "import os" "os.getenv('HOME')"
500000 loops, best of 5: 809 nsec per loop
```

`os.getenv`'s usage is quite similar to `os.environ.get()`, it has the same parameters and behavior:

```python
>>> import os
>>> bar = os.getenv("BAR")
>>> print(bar)
None
>>> bar = os.getenv("BAR", "bar")
>>> print(bar)
bar
```

## Accessing variables in a `.env` file

Sometimes, we would like to write our own environment variables without interfering with other programs, whether it's to store sensitive data or just configuration options, a `.env` file is what you need.

### Accessing the file using `configparser`

The main drawback of using `configparser` with .env files is that `configparser` **requires** sections. Which means that your .env file will have to look like this:

```shell
[SECTION1]
VAR_1=foo
```

Accessing the variables:

```python
>>> import configparser
>>> config = configparser.ConfigParser()
>>> config.read(".env")
>>> var_1 = config["SECTION1"]["VAR_1"]
>>> print(var_1)
"foo"
```

### Accessing the file using `python-dotenv`

 [`python-dotenv`](https://pypi.org/project/python-dotenv/) is a Python library which allows us to read environment variables from a `.env` file using the `os` module:

```shell
# Our .env file
FOO=bar
```

```python
>>> import os
>>> from dotenv import load_dotenv
>>>
>>> load_dotenv()
>>> foo = os.getenv("FOO")
>>> print(foo)
"bar"
```

`load_dotenv()` will search for a `.env` file in the current directory or parent directories by default, and then loads them to make them accessible by your project. But you can also manually specify a directory:

```python
...
load_dotenv("path/to/.env")
...
```

## Use case: Managing sensitive data

Let's say you were working with API tokens, and didn't want to hardcode them into your code, and risk accidentally pushing it to some version control software. You would use environment variables to store your token.


```shell
# .env
TOKEN=abcdefg12345
```

```python
import os
from dotenv import load_dotenv

load_dotenv()
token = os.getenv("TOKEN")

# Do stuff with the token
...
```

## Conclusion

In this tutorial we learned how to use the `os` module to access host environment variables, and also how to access variables stored in a `.env` file using `configparser` and `python-dotenv`.

## Further Reading

* [Relevant Stack Overflow question](https://stackoverflow.com/q/63019506)
* [`os.getenv`](https://docs.python.org/3/library/os.html?highlight=os%20getenv#os.getenv)
* [`os.environ`](https://docs.python.org/3/library/os.html?highlight=os%20getenv#os.environ)