5 Fitur Python yang Berguna—Beserta Batas dan Jebakannya

Assignment expression, dataclass, lru_cache, zip strict, dan generator dengan contoh, batas versi, serta jebakan yang perlu diuji.

· · 6 min read

5 Fitur Python yang Berguna—Beserta Batas dan Jebakannya

Sintaks yang pendek bukan selalu kode yang lebih baik. Fitur Python berikut berguna ketika membuat maksud kode lebih jelas atau mengurangi pekerjaan berulang, tetapi masing-masing mempunyai batas yang perlu dipahami.

Contoh menggunakan Python modern. Periksa versi minimum proyek sebelum menyalin fitur seperti assignment expression, dataclass(slots=True), atau zip(strict=True).

---

1. Assignment Expression untuk Menghindari Perhitungan Ganda

Operator :=, sering disebut walrus operator, memberi nilai di dalam expression:

while chunk := file.read(8192):
process(chunk)

Tanpanya, pembacaan sering ditulis dua kali:

chunk = file.read(8192)
while chunk:
process(chunk)
chunk = file.read(8192)

Contoh lain adalah menyimpan hasil komputasi yang dipakai untuk filter dan output:

large_files = [
(path, size)
for path in paths
if (size := path.stat().st_size) > 10_000_000
]

Gunakan ketika assignment membuat alur lebih mudah dibaca. Hindari memasukkan banyak assignment dan kondisi ke satu baris; statement biasa sering lebih jelas.

---

2. dataclass untuk Object Data, Bukan Semua Class

@dataclass menghasilkan metode seperti init, repr, dan eq berdasarkan field:

from dataclasses import dataclass, field

@dataclass(frozen=True, slots=True)
class Product:
sku: str
price_cents: int
tags: tuple[str, ...] = field(default_factory=tuple)

def post_init(self) -> None:
if self.price_cents tuple[str, int]:
print("loading", country_code)
return load_rule_from_static_file(country_code)

Argumen harus hashable. Cache paling aman untuk fungsi yang hasilnya stabil untuk input yang sama.

Hindari cache pada:

• fungsi dengan side effect;
• data yang harus selalu segar;
• hasil mutable yang kemudian dimodifikasi caller;
• kombinasi argumen dengan cardinality sangat besar;
• data per-user atau rahasia tanpa isolasi yang jelas.

Pantau efektivitas:

info = parse_currency_rule.cache_info()
print(info.hits, info.misses, info.currsize)

parse_currency_rule.cache_clear()

Cache ini hidup di memory satu process. Beberapa worker memiliki cache terpisah, dan restart menghapus seluruh isi. Untuk data terdistribusi atau invalidation lintas process, dibutuhkan desain lain.

---

4. zip(strict=True) untuk Mendeteksi Data Tidak Sejajar

Secara default, zip() berhenti pada iterable terpendek:

names = ["Ayu", "Bima", "Citra"]
scores = [90, 85]

print(list(zip(names, scores)))
[('Ayu', 90), ('Bima', 85)]

Citra hilang tanpa error. Jika panjang seharusnya sama, gunakan strict mode:

pairs = list(zip(names, scores, strict=True))
ValueError: zip() argument 2 is shorter than argument 1

Ini berguna saat menggabungkan kolom CSV, hasil batch, atau array yang memiliki invariant panjang sama. Jangan gunakan strict jika pemotongan ke input terpendek memang perilaku yang diinginkan.

Untuk memperoleh index sekaligus pasangan:

for row_number, (name, score) in enumerate(
zip(names, scores, strict=True),
start=1,
):
print(row_number, name, score)

---

5. Generator untuk Streaming, List untuk Dipakai Berulang

List comprehension membangun seluruh hasil:

squares = [number * number for number in range(1_000_000)]

Generator expression menghasilkan item saat diminta:

squares = (number * number for number in range(1_000_000))
total = sum(squares)

Generator membantu ketika data besar, hanya dilalui sekali, atau sumbernya streaming. Namun generator akan habis:

values = (number * 2 for number in range(3))
print(list(values)) # [0, 2, 4]
print(list(values)) # []

Pilih list ketika perlu random access, panjang, iterasi berulang, atau dataset memang kecil. Jangan mengklaim generator “selalu lebih cepat”; ia biasanya menghemat memory, sementara overhead iterasi dan pola konsumsi menentukan waktu eksekusi.

---

Uji Perilaku, Bukan Hanya Output Bahagia

Fitur singkat mudah menyembunyikan asumsi. Tambahkan test untuk batas yang memang penting:

import pytest

def test_product_rejects_negative_price() -> None:
with pytest.raises(ValueError):
Product(sku="INVALID", price_cents=-1)

def test_zip_rejects_different_lengths() -> None:
with pytest.raises(ValueError):
list(zip(["A", "B"], [10], strict=True))

Untuk cache, uji invalidation dan object mutable. Jangan hanya memastikan call kedua lebih cepat. Jika fungsi membaca file konfigurasi, tentukan kapan cache dibersihkan setelah file berubah. Jika hasilnya list dan caller memodifikasinya, call berikutnya dapat menerima object yang sudah berubah.

@lru_cache(maxsize=32)
def get_roles(user_type: str) -> tuple[str, ...]:
return tuple(load_roles(user_type))

Mengembalikan tuple membantu mencegah modifikasi tidak sengaja, walaupun tidak menyelesaikan masalah data basi.

---

Ukur Memory dengan Alat yang Tepat

slots sering dipromosikan dengan angka penghematan besar. Angka itu bergantung pada versi dan implementasi Python, inheritance, jumlah field, serta object yang dirujuk.

sys.getsizeof(instance) hanya mengukur ukuran langsung object, bukan seluruh object graph. Untuk eksperimen:

import sys

regular = RegularProduct("SKU-1", 10_000)
slotted = SlottedProduct("SKU-1", 10_000)

print(sys.getsizeof(regular))
print(sys.getsizeof(regular.dict))
print(sys.getsizeof(slotted))

Gunakan tracemalloc atau profiler memory pada pembuatan banyak instance agar perbandingan lebih representatif. Jangan mengorbankan API class dan kemudahan debugging untuk penghematan yang tidak signifikan pada aplikasi Anda.

---

Kompatibilitas Versi

Assignment expression tersedia mulai Python 3.8, zip(strict=True) mulai 3.10, dan parameter slots=True pada dataclass juga mulai 3.10. Jika package mendukung beberapa versi, deklarasikan versi minimum pada metadata proyek dan jalankan test matrix.

Hindari fallback yang diam-diam mengubah semantik. Lebih baik menetapkan versi minimum yang jelas daripada menulis ulang zip(strict=True) menjadi zip() lalu kehilangan validasi panjang.

Type annotation membantu editor dan type checker, tetapi Python tidak memvalidasi tipe saat runtime secara otomatis. price_cents: int masih memerlukan validasi pada boundary jika data berasal dari JSON, form, database, atau pihak eksternal.

Jalankan formatter, linter, type checker, dan test pada versi minimum tersebut. Sebuah contoh yang berhasil di interpreter terbaru belum tentu valid pada runtime deployment. Dokumentasikan alasan memakai fitur khusus agar refactor berikutnya tidak menghapus invariant seperti pemeriksaan panjang strict atau batas ukuran cache.

---

Cara Memilih Fitur

Sebelum memakai fitur yang terlihat pintar, tanyakan:

1. Apakah maksud kode menjadi lebih mudah dibaca?
2. Apakah batas versi Python proyek mendukungnya?
3. Apakah ada state, mutability, atau invalidation tersembunyi?
4. Apakah manfaat memory/performa sudah diukur?
5. Apakah anggota tim mudah memeliharanya?

Fitur bahasa bernilai ketika memperjelas invariant dan menghapus bug, bukan ketika sekadar membuat kode lebih pendek.

Referensi

• Python: Assignment expressions
• Python: Data Classes
• Python: functools.lru_cache
• Python: zip
• Python: Generator expressions