Soal 1Di with X() as y:, nilai yang diikat ke y adalah nilai kembalian dari method mana?
Statement with dan Context Manager — Buka/Tutup Aman dengan __enter__ / __exit__
Pelajari statement with Python dan context manager. Pasangan __enter__ / __exit__ untuk buka/tutup aman, dan cara menulisnya sendiri — hands-on.
Sebelumnya kita bekerja melindungi state internal class. Kali ini kita melangkah satu lapis ke luar — ke resource eksternal yang berada di luar proses Python (file, koneksi database, socket jaringan, lock) — dan melihat statement with dan context manager yang menangani akuisisi dan pelepasan mereka dengan aman.
Kenapa Kamu Perlu Statement with
Operasi seperti membuka file atau menghubung ke database datang dengan tugas cleanup: "begitu selesai, tutup". Lupa menutup, dan kamu membocorkan file descriptor, memegang koneksi DB selamanya, dan meninggalkan proses eksternal masih menggenggam resource.
close(), sisi lain terus menunggu instruksi dan memegang resource.Kamu bisa menulis logika yang sama dengan try / finally, tetapi kemudian setiap penulis harus ingat memanggil close() di dalam finally setiap kali. Saat codebase tumbuh atau lebih banyak orang menyentuhnya, seseorang akan lupa — itu kenyataan.
Statement with menutup akuisisi dan pelepasan ke dalam satu unit sintaktis dan mengotomatiskannya. with open("file.txt") as f: adalah contoh kanonik: file dijamin tertutup begitu kamu meninggalkan blok with.
Menulis Context Manager Sendiri — __enter__ dan __exit__
Object yang bisa dipakai dengan with disebut context manager. Untuk membuat class menjadi satu, cukup implementasikan dua special method.
- __enter__(self) — berjalan saat kamu memasuki blok with. Nilai kembaliannya diikat ke variabel yang dinamai setelah as.
- __exit__(self, exc_type, exc_val, traceback) — berjalan saat kamu meninggalkan blok. Selalu dipanggil, keluar normal atau exceptional.
Contoh gaya koneksi DB minimal di bawah (kita tidak benar-benar memakai library DB — kita meniru dengan string).
class DatabaseManager:
def __init__(self, db_name):
self.db_name = db_name
self.connection = None # belum terhubung
def __enter__(self):
print(f"Connecting to {self.db_name}")
self.connection = f"connection_to_{self.db_name}" # kode nyata: object koneksi sebenarnya
return self.connection # nilai diikat ke variabel as
def __exit__(self, exc_type, exc_val, traceback):
print(f"Disconnecting from {self.db_name}")
self.connection = None # cleanup
return False # jangan menelan exception
with DatabaseManager("user_data_db") as conn:
print(f" active connection: {conn}")
print(" inserting data")
# ↑ saat blok ini keluar, __exit__ berjalan
Jalankan dan output muncul dalam urutan "hubung → kerja dalam blok → putus". Pemutusan berjalan tanpa siapa pun memanggilnya secara eksplisit — itulah seluruh nilai with. Developer terbebas dari khawatir menutup koneksi.
Tiga Argumen __exit__ — Menangkap Exception
__exit__ mengambil tiga argumen: exc_type, exc_val, traceback. Python memakai ini untuk memberitahu __exit__ apakah exception terjadi di dalam blok with.
- Keluar normal — ketiganya None. Cukup cleanup.
- Keluar exception — exc_type adalah class exception, exc_val adalah instance, traceback adalah object traceback.
Nilai kembalian __exit__ juga punya makna. Mengembalikan True menelan exception — itu tidak merambat di luar blok. Mengembalikan False / None mengangkat ulang setelah cleanup. Default seharusnya False (atau return tanpa apa-apa): log atau notifikasi, tetapi selalu biarkan exception lolos.
None × 3. Exception mengirim trio "class / instance / traceback". Sebuah raise ValueError("invalid") konkret membuat isinya nyata.Mengembalikan True dari __exit__ diam-diam membunuh exception
Kalau __exit__ mengembalikan True, exception di dalam with tidak merambat. Menggoda, tetapi pemanggil sekarang berpikir operasi berhasil — itu efek samping serius. Default ke False (atau tanpa return): log atau notifikasi kalau mau, tetapi selalu biarkan exception muncul ke atas.
Sekarang benar-benar picu exception di dalam with dan lihat apa yang mencapai tiga argumen __exit__.
Dibandingkan dengan try / finally — Kenapa with Menang
Tugas context manager bisa dilakukan dengan try / finally. Alasan memilih with sebagai gantinya adalah "pasangan buka/tutup tinggal di dalam class". Menulis tugas yang sama dengan dua cara membuat perbedaan dalam volume kode pemanggil dan kejernihan menjadi jelas.
# ❌ try / finally — pemanggil menulis cleanup setiap kali
db = DatabaseManager("shop_db")
conn = db.open() # method connect kustom
try:
use(conn) # kerja sebenarnya
finally:
db.close() # jangan lupa — disalin di mana-mana
# ✅ with — buka/tutup tinggal di class, pemanggil hanya melakukan kerja
with DatabaseManager("shop_db") as conn:
use(conn) # tidak perlu finally
- Pemanggil — harus menulis
try/finallysetiap kali - Lupa — satu copy-paste buruk dan leak muncul
- Biaya perubahan — langkah cleanup ekstra berarti mengedit setiap tempat panggil
- Pemanggil — satu baris,
with X() as y: - Lupa — mustahil di tingkat sintaks (
__exit__selalu berjalan) - Biaya perubahan — cleanup ekstra berarti mengedit hanya
__exit__
with. Saat tempat panggil berlipat ganda, perubahan cleanup tetap tinggal di dalam satu class.Pakai with di mana pun akuisisi dan pelepasan berpasangan
File, koneksi DB, lock, socket jaringan — di mana pun kamu "meraih resource di awal dan harus mengembalikannya di akhir" — adalah kandidat untuk with. Library standar Python sudah mengekspos banyak dari ini sebagai context manager: open(), threading.Lock(), sqlite3.connect(), dan seterusnya.
Cek Pemahaman
Jawab setiap pertanyaan satu per satu.
Soal 2Saat exception dimunculkan di dalam blok with, mana yang menggambarkan perilaku __exit__ dengan benar?
Soal 3Kalau __exit__ mengembalikan True, apa yang terjadi pada exception yang dimunculkan di dalam blok with?