Kursus Python / Mengatur perubahan objek dengan metode dan property
Metode menyatakan operasi objek, sedangkan property mempertahankan sintaks akses atribut sambil menerapkan aturan pembacaan atau penulisan. Dengan property, nilai awal dan perubahan berikutnya dapat melewati pemeriksaan yang sama.
Pisahkan antarmuka publik dari tempat penyimpanan
Antarmuka publik contoh ini bernama amount, sedangkan nilai disimpan pada atribut internal _amount. Awalan garis bawah memberi petunjuk bahwa atribut itu merupakan rincian implementasi. Ia tidak melarang kode luar mengaksesnya dan bukan pengamanan untuk menyimpan rahasia.
Membaca item.amount memanggil getter. Memberi nilai melalui item.amount = value memanggil setter. Pemanggil memakai bentuk atribut tanpa tanda kurung; ini berbeda dari operasi seperti item.add_fee(500). Dasar pembuatannya ada pada dokumentasi property Python.
Pada contoh class dan initializer, pemeriksaan saat pembuatan saja belum mengendalikan perubahan kemudian. Di sini, __init__ menggunakan self.amount = amount sehingga nilai awal ikut melewati setter. Menulis langsung ke _amount di initializer akan melewati aturan property tersebut.
Jalankan perubahan yang valid dan yang ditolak
Simpan program lengkap berikut sebagai properties.py dengan encoding UTF-8. Gunakan Python 3.12 atau lebih baru melalui lingkungan proyek, lalu jalankan python properties.py. Contoh tidak memerlukan paket atau berkas data tambahan.
class Expense:
def __init__(self, amount):
self.amount = amount
@property
def amount(self):
return self._amount
@amount.setter
def amount(self, value):
if type(value) is not int or value < 0:
raise ValueError("amount must be a nonnegative integer")
self._amount = value
def add_fee(self, fee):
self.amount = self.amount + fee
item = Expense(8000)
item.add_fee(500)
print(item.amount)
try:
item.amount = -1
except ValueError:
print("rejected")
print(item.amount)
Keluaran yang diharapkan:
8500
rejected
8500
Pembuatan objek menyimpan 8000 melalui setter. Metode add_fee membaca jumlah, menghitung 8500, lalu memberikan hasil melalui setter yang sama. Ketika -1 ditetapkan, pemeriksaan menaikkan ValueError sebelum penyimpanan, sehingga jumlah lama tetap 8500 setelah penolakan.
type(value) is not int menyatakan kebijakan menerima integer biasa saja. Dengan aturan tersebut, True ditolak sebagai nilai jumlah walaupun boolean merupakan subclass integer, begitu juga 3.5 atau string angka. Ini keputusan antarmuka contoh, bukan aturan wajib untuk setiap property.
| Bentuk akses | Perilaku pada contoh |
|---|---|
item.amount |
Getter membaca _amount |
item.amount = 100 |
Setter memvalidasi lalu menyimpan |
item.add_fee(500) |
Metode menghitung perubahan dan memakai setter |
Hindari rekursi dan perubahan sebagian
Setter harus menyimpan hasil ke atribut pendukung seperti self._amount. Jika baris terakhir diganti menjadi self.amount = value, setter memanggil dirinya lagi. Pemanggilan itu berulang sampai gagal dengan RecursionError. Getter juga harus membaca atribut pendukung, bukan mengakses property yang sama tanpa jalan keluar.
Lakukan validasi sebelum mengubah keadaan. Jika nilai salah disimpan terlebih dahulu baru pengecualian dinaikkan, pemanggil mendapat kegagalan tetapi objek mungkin sudah tidak valid. Uji keduanya: jenis kegagalan dan keadaan yang tersisa setelah kegagalan.
Jangan menyembunyikan permintaan jaringan atau pembacaan berkas besar di balik akses yang tampak sebagai pembacaan atribut sederhana. Metode bernama jelas biasanya lebih mudah menyampaikan bahwa ada pekerjaan mahal, efek samping, atau kemungkinan gagal.
Property tanpa setter menolak pemberian nilai biasa melalui property tersebut. Namun atribut pendukung atau bagian lain objek masih dapat berubah. Antarmuka baca-saja tidak membuat seluruh objek menjadi immutable secara mendalam, dan konvensi garis bawah tidak membatasi kode luar secara keamanan.
Uji aturan jumlah dan aturan biaya secara terpisah
- Jalankan sumber asli dan cocokkan 8500,
rejected, lalu 8500 lagi. Nilai terakhir memeriksa bahwa pembaruan gagal tidak merusak keadaan. - Coba menetapkan
Truedan 3.5 padaamountsecara terpisah dengan penanganValueError. Setelah masing-masing penolakan, pastikan nilai tetap 8500. - Coba
add_fee(-500)dari keadaan 8500. Contoh mengizinkan hasil 8000. Sebaliknya, biaya -9000 membuat hasil negatif dan ditolak tanpa mengganti jumlah sebelumnya. - Pulihkan program asli setelah percobaan dan cocokkan kembali keluarannya sebelum memperluas aturan.
Validasi hasil jumlah tidak otomatis memvalidasi arti biaya. Misalnya, add_fee(True) dapat menambah 1 karena operasi penjumlahan menghasilkan integer yang memenuhi setter. Jika biaya harus integer biasa dan nonnegatif, metode perlu memeriksa tipe serta rentang fee sendiri sebelum menghitung hasil.
Tentukan apakah biaya negatif memang berarti potongan yang sah atau masukan yang harus ditolak. Pertahankan aturan jumlah dan aturan operasi sebagai dua kontrak yang eksplisit. Property membantu mengarahkan akses, tetapi konsistensi rancangan dan pengujian tetap menentukan nilai apa yang diterima.




