Soal 1Mana pernyataan paling akurat tentang variabel private Python?
Variabel Private dan Encapsulation — Akses Aman lewat getter / setter
Pelajari variabel private dan encapsulation di Python. Konvensi _x vs name mangling __x, get_xxx / set_xxx untuk akses aman, dan gaya Pythonic @property / @xxx.setter — semua hands-on.
Sebelumnya kita membahas dua pilar pertama OOP — pewarisan dan polimorfisme. Artikel ini menutup pilar ketiga: encapsulation.
Variabel Private — Python Tidak Punya Privasi Sungguhan
Java dan C++ punya keyword private yang memblokir akses dari luar saat kamu mendeklarasikannya. Python tidak punya privasi yang ditegakkan bahasa. Sebagai gantinya, jumlah underscore di depan menjadi sinyal "ini untuk pemakaian internal" atau "jangan disentuh langsung" — sebuah konvensi antar programmer, bukan aturan keras.
Single underscore _x — privasi konvensi saja
Menambahkan satu _ di depan nama memberitahu komunitas Python "atribut ini untuk pemakaian internal class — jangan diakses langsung dari luar". Parameter __init__ tetap memakai nama biasa; hanya field self. yang diberi awalan _.
class UserAccount:
def __init__(self, owner_name, balance):
self._owner_name = owner_name # internal -> diawali _
self._balance = balance
def get_info(self): # accessor menghadap luar
return {"owner": self._owner_name, "balance": self._balance}
user = UserAccount("Budi", 50000)
print(user._balance) # 50000 <- jalan tetapi tidak disarankan
print(user.get_info()) # {'owner': 'Budi', 'balance': 50000} <- disarankan
Double underscore __x — name mangling
Menambahkan dua _ di depan membuat Python menulis ulang nama atributnya sendiri. Kalau kamu menulis self.__pin = 1234 di dalam class Account, nama yang sebenarnya disimpan menjadi _Account__pin. Ini disebut name mangling — obj.__pin dari luar tidak menemukan apa-apa, jadi akses secara efektif jauh lebih sulit.
obj.__pin langsung gagal dengan AttributeError karena key itu tidak ada di sana.class Account:
def __init__(self, owner, pin):
self._owner = owner # privasi konvensi saja
self.__pin = pin # name-mangled (jadi _Account__pin)
acc = Account("Budi", 1234)
print(acc._owner) # Budi <- jalan normal
# print(acc.__pin) # AttributeError <- tidak terlihat langsung
print(acc._Account__pin) # 1234 <- nama mangled menjangkaunya
"__" juga bukan tembok mutlak
Double underscore mencegah akses obj.__pin langsung, yang satu tingkat lebih kuat. Tetapi siapa pun yang tahu nama mangled obj._Account__pin masih bisa menjangkaunya. Ini bukan privasi sungguhan. Di proyek nyata, single underscore _x jauh lebih umum kecuali ada alasan spesifik untuk memakai mangling.
Encapsulation — batasi akses ke method khusus
Encapsulation adalah ide desain "bundel atribut data dan method yang mengoperasikannya ke dalam satu class, dan paksa kode luar untuk masuk lewat sekumpulan kecil entry point yang dipublikasikan". Jadi bagaimana kita membangun entry point itu?
_price tanpa diperiksa. Lewat method berarti setter memvalidasi tipe dan range di satu tempat.Gaya paling dasar adalah menulis method get_xxx / set_xxx dengan tangan. Di dalam setter, lakukan pemeriksaan isinstance untuk tipe dan pemeriksaan range, dan raise ValueError(...) kalau ada yang salah. Dengan itu di tempat, tidak ada nilai sampah yang pernah mencapai _price.
class Product:
def __init__(self, name, price, stock):
self._name = name
self._price = price
self._stock = stock
def get_price(self):
return self._price
def set_price(self, price):
if isinstance(price, int) and price >= 0:
self._price = price
else:
raise ValueError("price must be a non-negative integer")
product = Product("Kaos", 1500, 30)
print(product.get_price()) # 1500
product.set_price(2000)
print(product.get_price()) # 2000
# product.set_price(-100) # ValueError
@property dan @xxx.setter
Gaya get_price() / set_price(...) jelas, tetapi tempat panggilnya jadi terlihat seperti panggilan method — bukan yang paling bersih. Idiom Python yang lebih halus memakai dua dekorator: @property dan @xxx.setter.
Dengan keduanya, tempat panggil tetap sebagai product.price / product.price = 2000 — akses atribut biasa — tetapi di bawahnya, method getter dan setter dipanggil. Itu struktur dua-lapis di mana sintaks tetap sederhana tetapi logika tetap berjalan.
@property mengarahkan ulang baca dan @price.setter mengarahkan ulang tulis ke panggilan method. Validasi tinggal di dalam setter.class Product:
def __init__(self, name, price):
self._name = name
self._price = price
@property
def price(self): # getter
return self._price
@price.setter
def price(self, value): # setter — nama harus sama dengan getter
if not isinstance(value, int) or value < 0:
raise ValueError("price must be a non-negative integer")
self._price = value
@property
def label(self): # computed property — nilai turunan
return f"{self._name} ({self._price})"
product = Product("Kaos", 1500)
print(product.price) # 1500 <- @property dipanggil
product.price = 2000 # <- @price.setter dipanggil
print(product.price) # 2000
print(product.label) # Kaos (2000) <- computed property
Jaga nama setter identik dengan getter
price di @price.setter harus cocok dengan nama method dari @property def price sebelumnya. Python menafsirkan dekorator itu sebagai "tempelkan versi tulis ke object price sama yang sudah punya versi baca" — kalau nama melenceng, keduanya diperlakukan sebagai hal terpisah.
Tiga Pilar OOP
- Proteksi data — pisahkan state internal dari API publik via
_x - Konsistensi — pusatkan validasi di setter, satu tempat
- Kebebasan implementasi — ubah internal tanpa mengubah API publik
- Gaya Pythonic — konvensi plus
@property, bukan penegakan bahasa
- Pakai ulang mesin induk
- Nama method sama, perilaku beda per tipe
- Salurkan akses luar lewat sekumpulan kecil pintu
Cek Pemahaman
Jawab setiap pertanyaan satu per satu.
Soal 2Apa manfaat terbesar memakai @property dan @xxx.setter?
Soal 3Di dalam class Account: kamu menulis self.__pin = 1234. Dari luar, acc.__pin memunculkan AttributeError. Nama apa yang sebenarnya tersimpan di instance?