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:

python
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:

text
MODE_APLIKASI : produksi
zona default  : Asia/Jakarta
setdefault    : INFO / produksi

Mari kita bedah pola aksesnya:

  1. 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.
  2. Baris 6 (os.environ.get("ZONA_WAKTU", "Asia/Jakarta")): mengembalikan nilai default ketika variabel belum ada, sehingga program tidak gagal.
  3. Baris 8-9 (setdefault): hanya menetapkan nilai bila variabel belum ada. Karena MODE_APLIKASI sudah berisi "produksi", nilainya tidak tertimpa.

Perilaku tiap pola akses dirangkum berikut:

PolaPerilaku 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:

text
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:

python
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:

text
tanpa env : TOKEN = (kosong)
dengan env: TOKEN = YOUR_API_TOKEN

Baris 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.

ini
MODE_APLIKASI=produksi
LOG_LEVEL=INFO

Dengan library python-dotenv terpasang, pemuatannya hanya dua baris. Simpan sebagai baca_dotenv.py:

python
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:

text
MODE_APLIKASI: produksi
LOG_LEVEL   : INFO

Urutan 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:

PrioritasSumberAlasan
1argumen CLIpaling eksplisit, menang untuk percobaan cepat
2environment variableper lingkungan, cocok untuk container dan CI
3berkas konfigurasipengaturan stabil jangka panjang
4default dalam kodejaring pengaman terakhir

Fungsi kecil berikut menerapkan urutan tersebut — nilai pertama yang tidak None menang:

python
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:

text
host: example.com

Begitu APP_HOST ditetapkan di lingkungan (APP_HOST=api.example.com python3 urutan_prioritas.py), environment variable menimpa berkas:

text
host: api.example.com

Berkas konfigurasi pada lapisan ketiga itulah topik Chapter Konfigurasi dengan TOML, JSON, dan YAML berikutnya, tempat kita membangun pemuatan berlapis secara utuh.