Tidak semua data layak disimpan di setiap object. Total koleksi perpustakaan, batas maksimal pinjam, lokasi rak penyimpanan — nilai-nilai seperti ini dimiliki bersama oleh seluruh instance. Menyalinnya ke setiap object memboroskan memori dan, lebih buruk, rawan tidak sinkron antar object. Python menyediakan tempat yang tepat untuk data bersama: class attribute, yang ditulis langsung di body class. Chapter ini membahas cara kerjanya, relasinya dengan urutan pencarian attribute, dan satu jebakan terkenal yang wajib dihindari.
Data Bersama di Level Class #
Class attribute ditulis langsung di body class, di luar method apa pun. Statement class dieksekusi sekali saat modul dimuat, dan assignment di body class menempel pada object class itu sendiri. Kegunaan paling umum: penghitung (counter) yang melacak berapa banyak object yang pernah dibuat:
class Buku:
jumlah_buku = 0
def __init__(self, judul, penulis):
self.judul = judul
self.penulis = penulis
Buku.jumlah_buku += 1
buku1 = Buku("Laskar Pelangi", "Andrea Hirata")
buku2 = Buku("Bumi Manusia", "Pramoedya A. Toer")
buku3 = Buku("Negeri 5 Menara", "A. Fuadi")
print("Total buku terdaftar:", Buku.jumlah_buku)Output yang Dihasilkan:
Total buku terdaftar: 3Mari kita telaah baris-baris kode di atas:
- Baris 2 (
jumlah_buku = 0): nilai0disimpan sekali pada object classBuku— bukan pada tiap instance. - Baris 7 (
Buku.jumlah_buku += 1): setiap kali__init__berjalan, penghitung di class bertambah satu. Pembaruan dilakukan lewat nama class (Buku.jumlah_buku), bukan lewatself. - Baris 13: setelah tiga object dibuat, nilai bersama di class menjadi
3.
Pembaruan lewat nama class itu penting. Jika kita menulis self.jumlah_buku += 1, Python membaca nilai dari class lalu menulis hasilnya sebagai attribute instance — penghitung di class tidak pernah bertambah, dan tiap object justru membawa salinan angkanya sendiri.
Perubahan di Class Terlihat oleh Semua Instance #
Pada Chapter Instance Attributes kita melihat bahwa pencarian attribute berhenti di instance jika ditemukan; jika tidak, pencarian jatuh ke class. Konsekuensinya: mengubah class attribute langsung mengubah hasil pembacaan di semua instance yang tidak menimpanya:
class Buku:
lokasi_rak = "Rak A"
def __init__(self, judul):
self.judul = judul
buku1 = Buku("Laskar Pelangi")
buku2 = Buku("Bumi Manusia")
print(buku1.lokasi_rak)
print(buku2.lokasi_rak)
Buku.lokasi_rak = "Rak B"
print(buku1.lokasi_rak)
print(buku2.lokasi_rak)Output yang Dihasilkan:
Rak A
Rak A
Rak B
Rak BKedua object awalnya sama-sama membaca "Rak A" lewat mekanisme fallback ke class. Begitu Buku.lokasi_rak diubah menjadi "Rak B", kedua pembacaan langsung ikut berubah — tanpa satu pun object menyimpan datanya sendiri. Inilah perilaku “data bersama” yang dicari dari class attribute.
Jebakan Mutable Class Attribute #
Perhatikan dua perpustakaan berikut yang seharusnya punya daftar genre masing-masing:
class Perpustakaan:
daftar_genre = []
def __init__(self, nama):
self.nama = nama
def tambah_genre(self, genre):
self.daftar_genre.append(genre)
perpus_kota = Perpustakaan("Perpustakaan Kota")
perpus_sekolah = Perpustakaan("Perpustakaan Sekolah")
perpus_kota.tambah_genre("Fiksi")
perpus_sekolah.tambah_genre("Biografi")
print("Genre Perpustakaan Kota:", perpus_kota.daftar_genre)
print("Genre Perpustakaan Sekolah:", perpus_sekolah.daftar_genre)Output yang Dihasilkan:
Genre Perpustakaan Kota: ['Fiksi', 'Biografi']
Genre Perpustakaan Sekolah: ['Fiksi', 'Biografi']Kedua perpustakaan menampilkan isi yang sama persis. Mari kita bedah penyebabnya:
- Baris 2 (
daftar_genre = []): satu objectlistdibuat dan disimpan di class. - Baris 8 (
self.daftar_genre.append(genre)): pembacaanself.daftar_genretidak menemukan attribute di instance, jadi pencarian jatuh ke class dan menemukan list bersama. Method.append()lalu memutasi list tersebut di tempat. - Kedua pemanggilan
tambah_genre()mengubah list yang sama — genre dari dua perpustakaan bercampur jadi satu.
Perbaikannya: pindahkan pembuatan list ke __init__ agar setiap instance mendapat list sendiri:
class Perpustakaan:
def __init__(self, nama):
self.nama = nama
self.daftar_genre = []
def tambah_genre(self, genre):
self.daftar_genre.append(genre)
perpus_kota = Perpustakaan("Perpustakaan Kota")
perpus_sekolah = Perpustakaan("Perpustakaan Sekolah")
perpus_kota.tambah_genre("Fiksi")
perpus_sekolah.tambah_genre("Biografi")
print("Genre Perpustakaan Kota:", perpus_kota.daftar_genre)
print("Genre Perpustakaan Sekolah:", perpus_sekolah.daftar_genre)Output yang Dihasilkan:
Genre Perpustakaan Kota: ['Fiksi']
Genre Perpustakaan Sekolah: ['Biografi']Aturan praktisnya mudah diingat: nilai immutable (angka, string, tuple) aman sebagai class attribute; object mutable (list, dict, set) hampir selalu lebih tepat menjadi instance attribute.
Konstanta di Level Class #
Class attribute juga tempat alami bagi konstanta — nilai tetap yang dipakai bersama dan tidak pernah diubah selama program berjalan. Konvensi Python menuliskannya dengan huruf KAPITAL:
class Buku:
MAKS_PINJAM = 3
def __init__(self, judul):
self.judul = judul
def masih_bisa_dipinjam(self, jumlah_dipinjam):
return jumlah_dipinjam < Buku.MAKS_PINJAM
buku = Buku("Laskar Pelangi")
print(buku.masih_bisa_dipinjam(2))
print(buku.masih_bisa_dipinjam(3))Output yang Dihasilkan:
True
FalseNilai MAKS_PINJAM tinggal satu tempat: mengubah batas pinjam hanya perlu menyentuh satu baris. Untuk sekumpulan konstanta yang membentuk pilihan tetap (hari, status, kategori), Python menyediakan enum yang lebih terstruktur — dibahas pada chapter Enum di Section Advanced Data Modeling.
Dengan attribute dan datanya beres, saatnya memberi perilaku: Chapter Instance Methods membahas apa yang sebenarnya terjadi ketika sebuah method dipanggil.