Program yang sama sering harus berjalan dengan pengaturan berbeda: di laptop memakai server lokal, di server produksi memakai database sungguhan, di CI memakai mode pengujian. Environment variables menyelesaikan masalah ini dengan mengirim konfigurasi melalui lingkungan proses, bukan lewat kode yang harus diubah. Pada Chapter ini kita membaca dan menetapkan environment variables dari Python, mengelola secrets, dan menetapkan urutan prioritas konfigurasi.
Membaca dengan os.environ #
Object os.environ adalah mapping dari nama variabel ke nilai string, mirip dictionary. Simpan berikut sebagai baca_env_variabel.py:
import os
os.environ["MODE_APLIKASI"] = "produksi"
print("MODE_APLIKASI :", os.environ["MODE_APLIKASI"])
print("zona default :", os.environ.get("ZONA_WAKTU", "Asia/Jakarta"))
os.environ.setdefault("LOG_LEVEL", "INFO")
os.environ.setdefault("MODE_APLIKASI", "pengembangan")
print("setdefault :", os.environ["LOG_LEVEL"], "/", os.environ["MODE_APLIKASI"])Output yang Dihasilkan:
MODE_APLIKASI : produksi
zona default : Asia/Jakarta
setdefault : INFO / produksiMari kita bedah pola aksesnya:
- Baris 3 (
os.environ["MODE_APLIKASI"] = "produksi"): menetapkan variabel pada proses Python yang sedang berjalan; variabel ini ikut terlihat oleh proses anak yang dibuat setelahnya. - Baris 6 (
os.environ.get("ZONA_WAKTU", "Asia/Jakarta")): mengembalikan nilai default ketika variabel belum ada, sehingga program tidak gagal. - Baris 8-9 (
setdefault): hanya menetapkan nilai bila variabel belum ada. KarenaMODE_APLIKASIsudah berisi"produksi", nilainya tidak tertimpa.
Perilaku tiap pola akses dirangkum berikut:
| Pola | Perilaku saat variabel tidak ada |
|---|---|
os.environ["NAMA"] | memicu KeyError |
os.environ.get("NAMA") | mengembalikan None |
os.environ.get("NAMA", "default") | mengembalikan "default" |
os.environ.setdefault("NAMA", "nilai") | menetapkan "nilai", lalu mengembalikannya |
KeyError yang muncul dari akses langsung terlihat seperti ini:
KeyError: 'TIDAK_ADA'Menetapkan Variabel untuk Proses Anak #
Perubahan pada os.environ berlaku untuk seluruh sisa hidup proses dan diwarisi semua proses anak. Untuk memberi lingkungan berbeda pada satu anak saja, salin mapping tersebut dan berikan lewat parameter env= pada subprocess.run(). Berkas env_anak.py berikut membandingkan keduanya:
import os
import subprocess
perintah = ["python3", "-c", "import os; print('TOKEN =', os.environ.get('TOKEN', '(kosong)'))"]
env_anak = os.environ.copy()
env_anak["TOKEN"] = "YOUR_API_TOKEN"
hasil = subprocess.run(perintah, capture_output=True, text=True)
print("tanpa env :", hasil.stdout.strip())
hasil = subprocess.run(perintah, capture_output=True, text=True, env=env_anak)
print("dengan env:", hasil.stdout.strip())Output yang Dihasilkan:
tanpa env : TOKEN = (kosong)
dengan env: TOKEN = YOUR_API_TOKENBaris env_anak = os.environ.copy() mencegah kita mengubah lingkungan proses induk; variabel TOKEN hanya menempel pada panggilan kedua. Pola salin-modifikasi-kirim ini adalah cara aman mengoper secret ke satu tool tanpa membocorkannya ke seluruh sistem.
PATH dan Menjalankan Program #
Saat kita mengetik python3 di terminal tanpa path lengkap, shell mencari berkas python3 yang dapat dieksekusi pada daftar folder bernilai variabel PATH. Daftar tersebut dipisahkan karakter : pada Linux dan macOS (; pada Windows), dan pencarian berlangsung dari folder pertama sampai ditemukan. Karena itu, dua program bernama sama di dua folder berbeda bisa membuat versi yang salah yang terpilih — masalah klasik yang juga dibahas pada Chapter Memecahkan Masalah Instalasi. Dari Python, lokasi sebuah executable dapat diperiksa dengan shutil.which(), yang kita praktikkan pada Chapter Menjalankan Program Eksternal.
Secrets dan Pola .env #
Menaruh password atau API token langsung di kode adalah kebiasaan terburuk: nilai tersebut masuk ke version control dan terlihat oleh siapa pun yang membaca repositori. Environment variables memisahkan secret dari kode, namun mengetiknya di setiap terminal melelahkan. Pola .env mengatasinya: simpan secret pada berkas .env di root proyek, lalu muat berkas tersebut saat program berjalan.
MODE_APLIKASI=produksi
LOG_LEVEL=INFODengan library python-dotenv terpasang, pemuatannya hanya dua baris. Simpan sebagai baca_dotenv.py:
import os
from dotenv import load_dotenv
load_dotenv()
print("MODE_APLIKASI:", os.environ.get("MODE_APLIKASI"))
print("LOG_LEVEL :", os.environ.get("LOG_LEVEL"))Output yang Dihasilkan:
MODE_APLIKASI: produksi
LOG_LEVEL : INFOUrutan Prioritas Konfigurasi #
Satu pengaturan bisa datang dari empat sumber sekaligus: argumen command line, environment variable, berkas konfigurasi, dan nilai default dalam kode. Konvensi industri memberi urutan yang selalu sama:
| Prioritas | Sumber | Alasan |
|---|---|---|
| 1 | argumen CLI | paling eksplisit, menang untuk percobaan cepat |
| 2 | environment variable | per lingkungan, cocok untuk container dan CI |
| 3 | berkas konfigurasi | pengaturan stabil jangka panjang |
| 4 | default dalam kode | jaring pengaman terakhir |
Fungsi kecil berikut menerapkan urutan tersebut — nilai pertama yang tidak None menang:
import os
def nilai_akhir(cli, env, berkas, default):
for kandidat in (cli, env, berkas, default):
if kandidat is not None:
return kandidat
host = nilai_akhir(
cli=None,
env=os.environ.get("APP_HOST"),
berkas="example.com",
default="localhost",
)
print("host:", host)Tanpa APP_HOST, nilai dari berkas konfigurasi menang:
host: example.comBegitu APP_HOST ditetapkan di lingkungan (APP_HOST=api.example.com python3 urutan_prioritas.py), environment variable menimpa berkas:
host: api.example.comBerkas konfigurasi pada lapisan ketiga itulah topik Chapter Konfigurasi dengan TOML, JSON, dan YAML berikutnya, tempat kita membangun pemuatan berlapis secara utuh.