Python - dotenv 教學

在開發 Python 應用程式時,我們經常需要處理一些敏感資訊或設定值,例如 API 金鑰、資料庫密碼、或是不同部署環境(開發、測試、生產)的特定設定。將這些資訊直接寫在程式碼中不僅不安全,也難以管理。
這時候,python-dotenv 這個函式庫就能派上用場了!

什麼是 python-dotenv

python-dotenv 是一個簡單易用的 Python 函式庫,它可以幫助我們從一個名為 .env 的檔案中讀取鍵值對 (key-value pairs),並將它們載入到環境變數 (environment variables) 中。這樣一來,我們就可以將設定與程式碼分離,讓專案更加安全且易於維護。

為什麼要使用 dotenv

  • 安全性:避免將 API 金鑰、密碼等敏感資訊直接寫入程式碼,降低外洩風險。
  • 設定管理:方便管理不同環境(開發、測試、生產)的設定,只需修改 .env 檔案即可。
  • 程式碼整潔:將設定值與主要邏輯分離,讓程式碼更易讀、易懂。
  • 協作方便:團隊成員可以各自維護自己的 .env 檔案,而不需要將敏感資訊提交到版本控制系統 (如 Git)。

安裝 python-dotenv

安裝非常簡單,只需要使用 pip

1
pip install python-dotenv

如何使用?

建立 .env 檔案

首先,在你的專案根目錄下建立一個名為 .env 的檔案。這個檔案的格式很簡單,就是一行一個鍵值對,用 = 連接:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# .env 檔案範例
# 資料庫設定
DB_HOST=localhost
DB_PORT=5432
DB_USER=myuser
DB_PASSWORD=mypassword

# API 金鑰
API_KEY=your_secret_api_key_here

# 其他設定
DEBUG=True
APP_NAME="My Awesome App"
APP_HOST=localhost
APP_PORT=8000
BASE_URL=http://${APP_HOST}:${APP_PORT}/api # 使用了變數內插,後面會詳細說明

注意:

  • # 開頭的行是註解。
  • 不需要用引號將值包起來,除非值本身包含空格或特殊字元。
  • 鍵 (key) 通常使用大寫字母和底線。

在 Python 程式碼中載入環境變數

接著,在你的 Python 程式碼中,匯入 load_dotenv 函數並執行它。通常建議在程式的入口點(例如 main.pyapp.py)的開頭就載入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import os
# 建議同時匯入 find_dotenv 來更可靠地定位 .env 檔案
from dotenv import load_dotenv, find_dotenv

# 載入 .env 檔案中的環境變數
# 使用 find_dotenv() 會自動從目前腳本位置向上搜尋 .env 檔案,更為穩健
# 如果沒找到檔案,它預設不會報錯
load_dotenv(find_dotenv())

# 現在可以使用 os.getenv() 來取得環境變數
# 注意:os.getenv() 讀取的所有值預設都是字串!
db_host = os.getenv("DB_HOST")
db_user = os.getenv("DB_USER")
db_port_str = os.getenv("DB_PORT") # 讀取到的是字串 "5432"
api_key = os.getenv("API_KEY")
debug_mode_str = os.getenv("DEBUG") # 讀取到的是字串 "True"
app_port_str = os.getenv("APP_PORT") # 讀取到的是字串 "8000"


print(f"資料庫主機: {db_host}")
print(f"資料庫使用者: {db_user}")
print(f"API 金鑰 (前幾個字元): {api_key[:5]}...") # 避免完整印出金鑰
print(f"讀取到的除錯模式 (字串): {debug_mode_str}")
print(f"讀取到的資料庫埠號 (字串): {db_port_str}")

# 對於非字串類型,需要進行手動轉換
# 將讀取到的字串轉換為布林值
is_debug = debug_mode_str.lower() == 'true' if debug_mode_str else False
print(f"除錯模式 (布林值): {is_debug}")

# 將讀取到的字串轉換為整數
try:
db_port = int(db_port_str) if db_port_str else None
app_port = int(app_port_str) if app_port_str else 8000 # 或者提供數字預設值
print(f"資料庫埠號 (整數): {db_port}")
print(f"應用程式埠號 (整數): {app_port}")
except ValueError:
print("錯誤:埠號設定不是有效的數字!")
# 在實際應用中可能需要更完善的錯誤處理

# 如果環境變數不存在,os.getenv() 預設會回傳 None
non_existent_var = os.getenv("NON_EXISTENT_VAR")
print(f"不存在的變數: {non_existent_var}")

# 也可以提供預設值給 os.getenv(),如果變數不存在或為空,會使用預設值
default_var = os.getenv("ANOTHER_NON_EXISTENT_VAR", "預設值")
print(f"有預設值的變數: {default_var}")

進階用法

除了基本載入功能,python-dotenv 還提供了一些進階選項:

  • 指定 .env 檔案路徑 (dotenv_path):
    如果你不想使用預設的 .env 檔名或路徑,可以明確指定:

    1
    2
    # 假設你的設定檔在 'config/.env_prod'
    load_dotenv(dotenv_path='config/.env_prod')
  • 覆蓋現有環境變數 (override):
    預設情況下,load_dotenv() 不會覆蓋系統中已存在的同名環境變數。若希望 .env 檔案優先,設定 override=True

    1
    2
    # 即使系統已有 DEBUG 變數,也會被 .env 中的值覆蓋
    load_dotenv(override=True)
  • 變數內插 (Interpolation):
    .env 檔案支援變數引用,可以使用 ${VAR_NAME} 語法:

    1
    2
    3
    4
    # .env 檔案中
    APP_HOST=localhost
    APP_PORT=8000
    BASE_URL=http://${APP_HOST}:${APP_PORT}/api

    載入後,os.getenv("BASE_URL") 會得到 http://localhost:8000/api。

  • 自動尋找 .env 檔案 (find_dotenv):
    正如我們先前在基本用法中推薦的,find_dotenv() 是一個輔助函數,它會從執行 Python 腳本的目錄開始,逐層向上查找,直到找到指定的檔案(預設是 .env)或到達根目錄為止。這使得即使你的腳本是從專案的不同子目錄執行的,load_dotenv(find_dotenv()) 也能正確找到位於專案根目錄的 .env 檔案,因此更加穩健。

    1
    2
    3
    4
    5
    6
    # 回顧基本用法中的推薦寫法:
    from dotenv import load_dotenv, find_dotenv
    load_dotenv(find_dotenv())

    # 你也可以傳遞參數給 find_dotenv,例如指定不同的檔名或設定找不到時是否報錯:
    # load_dotenv(find_dotenv(filename='.env.prod', raise_error_if_not_found=True))
  • 讀取變數到字典 (dotenv_values):
    如果你不想修改 os.environ,只想讀取 .env 內容作為字典:

    1
    2
    3
    4
    from dotenv import dotenv_values
    config = dotenv_values(".env") # 回傳一個字典
    db_host = config.get("DB_HOST")
    print(f"從字典讀取 DB Host: {db_host}")

將 .env 加入 .gitignore

非常重要! 為了避免將敏感資訊提交到版本控制系統 (例如 Git),你應該將 .env 檔案加入到專案的 .gitignore 檔案中。在你的 .gitignore 檔案中加入一行:

1
2
3
4
5
6
7
8
# .gitignore

# 忽略 dotenv 環境檔案
.env

# 其他需要忽略的檔案或目錄...
__pycache__/
*.pyc

這樣一來,當你使用 Git 進行版本控制時,.env 檔案就不會被追蹤或提交了。

總結

python-dotenv 是一個非常實用且靈活的工具,可以幫助開發者更安全、更方便地管理 Python 專案中的設定和敏感資訊。透過將設定與程式碼分離,並搭配版本控制系統的忽略清單,可以有效提升專案的品質與安全性。下次開發 Python 專案時,試試看 dotenv 吧!

也許你也會想看看