{count, plural, one {Kursus} other {Kursus}}
Enkapsulasi adalah prinsip dasar berorientasi objek di Python. Ini melindungi kelas Anda dari perubahan atau penghapusan yang tidak disengaja serta mendorong keterpakaiulangan dan kemudahan pemeliharaan kode. Pertimbangkan definisi kelas sederhana berikut:
class Smartphone:
def __init__(self, brand, os):
self.brand = brand
self.os = os
iphone = Smartphone("Apple", "iOS 17")
Banyak programmer Python mendefinisikan kelas seperti ini. Namun, ini jauh dari praktik terbaik yang diikuti para Pythonista pro. Masalah dengan kelas ini terlihat jelas ketika Anda mencoba mengubah datanya:
iphone.os = "Android"
print(iphone.os)
Android
Bayangkan iPhone berjalan di Android — sungguh keterlaluan! Jelas, kita perlu menetapkan batasan dalam kelas kita agar pengguna tidak bisa mengubah atributnya sesuka hati.
Jika pun mereka memutuskan untuk mengubahnya, perubahan tersebut harus sesuai ketentuan kita, mengikuti aturan kita. Namun kita tetap ingin atribut .os atau .brand terlihat sama di permukaan.
Semua hal ini dapat ditingkatkan dengan enkapsulasi dan dalam tutorial ini, kita akan mempelajarinya secara menyeluruh. Mari mulai!
Bagaimana Enkapsulasi Dicapai di Python?
Python mendukung enkapsulasi melalui konvensi dan praktik pemrograman, bukan melalui pengubah akses yang dipaksakan. Anda lihat, prinsip mendasar di balik banyak desain kode Python adalah “Kita semua di sini orang dewasa.” Kita hanya dapat menerapkan enkapsulasi sebagai konvensi semata dan berharap pengembang Python lain mempercayai serta menghormati kode kita.
Di bahasa OOP lain seperti Java dan C++, enkapsulasi ditegakkan ketat dengan pengubah akses seperti public, private atau protected, tetapi Python tidak memiliki itu:
| Fitur | Python | Java | C++ |
|---|---|---|---|
| Pengubah akses | Tidak ada pengubah yang dipaksakan; menggunakan konvensi penamaan (_protected, __private) |
Ditegakkan dengan kata kunci public, protected, private |
Ditegakkan dengan kata kunci public, protected, private |
| Metode getter/setter | Opsional, sering digunakan dengan dekorator @property untuk akses terkontrol |
Praktik umum, biasanya diimplementasikan sebagai metode | Praktik umum, biasanya diimplementasikan sebagai metode |
| Akses Data | Dapat diakses melalui konvensi penamaan; bergantung pada kedisiplinan pengembang | Dikendalikan oleh pengubah akses; ditegakkan oleh kompilator | Dikendalikan oleh pengubah akses; ditegakkan oleh kompilator |
| Filosofi | "Kita semua orang dewasa di sini" - bergantung pada konvensi dan kepercayaan | Penegakan ketat kontrol akses | Penegakan ketat kontrol akses |
Jadi, sebagian besar, jika bukan semua, teknik enkapsulasi yang akan saya tunjukkan adalah konvensi Python. Konvensi ini mudah dilanggar jika Anda mau. Namun saya percaya Anda akan menghormati dan mengikutinya dalam proyek pengembangan Anda sendiri.
Pengubah akses di Python
Misalkan kita memiliki kelas sederhana berikut:
class Tree:
def __init__(self, height):
self.height = height
pine = Tree(20)
print(pine.height)
20
Kelas ini memiliki satu atribut height yang bisa kita cetak. Masalahnya, kita juga bisa mengubahnya sesuka hati:
pine.height = 50
pine.height
50
pine.height = "Grandma"
pine.height
'Grandma'
Jadi, bagaimana cara memberi tahu pengguna bahwa mengubah height itu terlarang? Kita bisa menjadikannya anggota terlindungi (protected) dengan menambahkan satu garis bawah di depan:
class Tree:
def __init__(self, height):
self._height = height
pine = Tree(20)
pine._height
20
Sekarang, orang yang paham konvensi ini akan tahu bahwa mereka hanya boleh mengakses atribut tersebut dan bahwa kita sangat tidak menyarankan mereka menggunakan serta mengubahnya. Namun jika mereka mau, mereka tetap bisa mengubahnya, oh iya.
Jadi, bagaimana cara mencegah itu juga? Dengan menggunakan konvensi lain — ubah atribut menjadi anggota privat dengan menambahkan dua garis bawah di depan:
class Tree:
def __init__(self, height):
self.__height = height
pine = Tree(20)
pine.__height
AttributeError: 'Tree' object has no attribute '__height'
Sekarang, Python akan menimbulkan error jika seseorang mencoba mengakses atribut tersebut, apalagi mengubahnya.
Namun Anda sadar apa yang baru saja kita lakukan? Kita menyembunyikan satu-satunya informasi terkait objek kita dari pengguna. Kelas kita jadi tidak berguna karena tidak memiliki atribut publik.
Lalu, bagaimana kita mengekspos tinggi pohon kepada pengguna namun tetap mengendalikan bagaimana atribut itu diakses dan diubah? Misalnya, kita ingin tinggi pohon berada dalam rentang tertentu dan hanya bernilai integer. Bagaimana menegakkannya?
Pada titik ini, teman Anda yang menggunakan Java mungkin menyela dan menyarankan penggunaan metode getter dan setter. Jadi, mari kita coba dulu:
class Tree:
def __init__(self, height):
self.__height = height
def get_height(self):
return self.__height
def set_height(self, new_height):
if not isinstance(new_height, int):
raise TypeError("Tree height must be an integer")
if 0 < new_height <= 40:
self.__height = new_height
else:
raise ValueError("Invalid height for a pine tree")
pine = Tree(20)
pine.get_height()
20
Dengan cara ini, Anda membuat atribut privat __height tetapi membiarkan pengguna mengakses dan mengubahnya secara terkontrol menggunakan metode get_height dan set_height.
pine.set_height(25)
pine.get_height()
25
Sebelum menetapkan nilai baru, set_height memastikan bahwa tinggi baru berada dalam rentang tertentu dan bertipe numerik.
pine.set_height("Password")
TypeError: Tree height must be an integer
Namun metode-metode ini terasa berlebihan untuk operasi sederhana. Selain itu, kurang sedap ditulis seperti ini:
# Increase height by 5
pine.set_height(pine.get_height() + 5)
Bukankah akan lebih indah dan mudah dibaca jika kita bisa menulis kode ini:
pine.height += 5
dan tetap menegakkan tipe data dan rentang yang benar untuk height? Jawabannya ya, dan kita akan mempelajari caranya di bagian berikut.
Menggunakan dekorator @property dalam kelas Python
Kita perkenalkan teknik baru — membuat property untuk atribut:
class Tree:
def __init__(self, height):
# First, create a private or protected attribute
self.__height = height
@property
def height(self):
return self.__height
pine = Tree(17)
pine.height
17
Kita ingin pengguna mengakses atribut tersembunyi bernama __height seolah-olah itu atribut normal bernama height. Untuk mencapainya, kita mendefinisikan metode bernama height yang mengembalikan self.__height dan menghiasinya dengan @property.
Sekarang, kita bisa memanggil height dan mengakses atribut privat:
pine.height
17
Namun bagian terbaiknya adalah pengguna tidak bisa mengubahnya:
pine.height = 15
AttributeError: can't set attribute 'height'
Jadi, kita tambahkan metode lain bernama height(self, new_height) yang dibungkus oleh dekorator height.setter. Di dalam metode ini, kita menerapkan logika yang menegakkan tipe data dan rentang yang diinginkan untuk height:
class Tree:
def __init__(self, height):
self.__height = height
@property
def height(self):
return self.__height
@height.setter
def height(self, new_height):
if not isinstance(new_height, int):
raise TypeError("Tree height must be an integer")
if 0 < new_height <= 40:
self.__height = new_height
else:
raise ValueError("Invalid height for a pine tree")
Sekarang, ketika pengguna mencoba mengubah atribut height, @height.setter akan dipanggil, sehingga memastikan nilai yang benar diteruskan:
pine = Tree(10)
pine.height = 33 # Calling @height.setter
pine.height = 45 # An error is raised
ValueError: Invalid height for a pine tree
Kita juga dapat menyesuaikan bagaimana atribut height diakses melalui notasi titik dengan @height.getter:
class Tree:
def __init__(self, height):
self.__height = height
@property
def height(self):
return self.__height
@height.getter
def height(self):
# You can return a custom version of height
return f"This tree is {self.__height} meters"
pine = Tree(33)
pine.height
'This tree is 33 meters'
Meskipun kita membuat pine dengan tinggi bertipe integer, kita bisa memodifikasi nilai tampilannya dengan @height.getter.
Itu adalah contoh bagaimana kita dapat meningkatkan enkapsulasi dalam kelas Python. Ingat, enkapsulasi tetaplah konvensi karena kita masih bisa membobol anggota privat internal __height:
pine._Tree__height = "Gotcha!"
pine.height
'This tree is Gotcha! meters'
Segala sesuatu dalam kelas Python bersifat publik, begitu juga metode privat. Ini bukan cacat desain melainkan perwujudan pendekatan “Kita semua orang dewasa di sini”.
Berikut ringkasan pengubah akses Python yang baru saja kita tinjau:
| Pengubah/Konvensi | Deskripsi | Contoh |
|---|---|---|
| Publik | Tingkat akses default; atribut dan metode dapat diakses dari luar kelas | self.attribute |
| Terlindungi (Protected) | Ditandai dengan satu garis bawah; konvensi untuk menandai akses yang sebagian dibatasi | self._attribute |
| Privat | Ditandai dengan dua garis bawah; name mangling memberikan pembatasan akses terbatas | self.__attribute |
| Property | Menyediakan akses terkontrol ke atribut privat menggunakan @property decorator |
@property def attribute(self): |
| Property hanya-baca | Tidak ada @attribute.setter; memungkinkan akses hanya-baca ke sebuah atribut |
@property def attribute(self): |
Praktik Terbaik Saat Menerapkan Enkapsulasi
Ada sejumlah praktik terbaik yang dapat Anda ikuti untuk memastikan kode Anda selaras dengan kode yang ditulis oleh OOPista berpengalaman lainnya:
- Buat atribut atau metode terlindungi atau privat jika hanya digunakan oleh Anda. Anggota terlindungi atau privat dikecualikan dari dokumentasi dan memberi sinyal kepada orang lain bahwa anggota tersebut dapat Anda ubah, sebagai pengembang, tanpa pemberitahuan, sehingga mencegah mereka menggunakannya.
- Anda tidak selalu harus membuat property untuk setiap atribut kelas. Untuk kelas besar dengan banyak atribut, menulis metode
attr.getterdanattr.setterbisa menjadi pekerjaan yang merepotkan. - Pertimbangkan untuk menimbulkan peringatan setiap kali pengguna mengakses anggota terlindungi (
_). - Gunakan anggota privat seperlunya, karena dapat membuat kode sulit dibaca bagi yang tidak terbiasa dengan konvensi.
- Utamakan kejelasan daripada kerumitan. Karena enkapsulasi bertujuan meningkatkan pemeliharaan kode dan perlindungan data, jangan sepenuhnya menyembunyikan detail implementasi penting dari kelas Anda.
- Jika Anda ingin membuat property hanya-baca, jangan implementasikan metode
@attr.setter. Pengguna akan dapat mengakses property tersebut tetapi tidak dapat mengubahnya. - Selalu ingat bahwa enkapsulasi adalah konvensi, bukan aspek yang dipaksakan oleh sintaks Python.
- Untuk kelas sederhana, pertimbangkan menggunakan dataclass yang memungkinkan Anda mengaktifkan enkapsulasi kelas dengan satu baris kode. Namun, dataclass cocok untuk kelas yang lebih sederhana dengan atribut dan metode yang dapat diprediksi. Lihat tutorial dataclass ini untuk mempelajari lebih lanjut.
Kesimpulan dan Sumber Lanjutan
Dalam tutorial ini, kita telah mempelajari salah satu pilar inti pemrograman berorientasi objek di Python: enkapsulasi.
Enkapsulasi memungkinkan Anda mendefinisikan akses terkontrol ke data yang disimpan di dalam objek kelas Anda. Ini memungkinkan Anda menulis kode yang bersih, mudah dibaca, dan efisien serta mencegah perubahan atau penghapusan data kelas secara tidak sengaja.
Berikut beberapa sumber terkait untuk meningkatkan pengetahuan OOP Anda:
FAQs
Bagaimana perbedaan enkapsulasi dan abstraksi di Python?
Enkapsulasi berkaitan dengan menggabungkan data dan metode yang beroperasi pada data dalam satu unit, seperti kelas, serta membatasi akses ke beberapa komponennya. Abstraksi, di sisi lain, berfokus pada penyembunyian kerumitan dengan hanya mengekspos bagian-bagian esensial. Sementara enkapsulasi menitikberatkan pada pembatasan akses, abstraksi menitikberatkan pada penyederhanaan interaksi.
Apakah enkapsulasi dapat digunakan dalam pemrograman fungsional, atau eksklusif untuk OOP?
Enkapsulasi adalah konsep yang sangat terkait dengan pemrograman berorientasi objek (OOP) dan umumnya tidak digunakan dalam pemrograman fungsional. Pemrograman fungsional menekankan imutabilitas dan fungsi tanpa status, berbeda dengan OOP yang berfokus pada objek dan pengkapsulan data di dalam objek tersebut.
Apa saja jebakan umum yang perlu dihindari saat menerapkan enkapsulasi di Python?
Jebakan umum termasuk terlalu banyak menggunakan variabel privat yang dapat membuat kode sulit dipelihara, dan tidak menyediakan metode akses yang memadai (getter/setter) yang dapat membuat kode rapuh. Selain itu, pengembang mungkin lupa bahwa enkapsulasi di Python bersifat konvensi, sehingga dapat diakali.
Bagaimana enkapsulasi dapat meningkatkan keamanan kode?
Enkapsulasi dapat meningkatkan keamanan kode dengan membatasi akses ke keadaan internal sebuah objek dan mencegah modifikasi yang tidak sah. Dengan mengendalikan bagaimana data diakses dan diubah, pengembang dapat memastikan data tetap valid dan konsisten.
Bagaimana penggunaan dekorator @property memengaruhi kinerja di Python?
Menggunakan @property dapat menimbulkan overhead kecil karena pemanggilan metode tambahan, namun dalam banyak kasus dampaknya dapat diabaikan. Manfaat peningkatan keterbacaan dan kemudahan pemeliharaan kode sering kali lebih besar daripada biaya kinerja yang kecil tersebut.
Apakah mungkin menegakkan enkapsulasi secara ketat di Python seperti di Java atau C++?
Python tidak menegakkan enkapsulasi secara ketat seperti Java atau C++. Filosofinya berbasis pada konvensi dan pemahaman bahwa pengembang akan menghormati penggunaan yang dimaksud dari anggota privat dan terlindungi. Namun, penggunaan konvensi penamaan seperti garis bawah dapat mengurangi penyalahgunaan.
Apa saja penerapan nyata enkapsulasi dalam proyek Python?
Enkapsulasi digunakan untuk melindungi data sensitif dalam aplikasi seperti perangkat lunak perbankan, di mana detail akun disembunyikan. Enkapsulasi juga digunakan dalam library dan framework untuk menyembunyikan detail implementasi yang kompleks, sehingga pengembang dapat berinteraksi melalui antarmuka yang sederhana.
Bagaimana cara menguji kode yang dienkapsulasi secara efektif di Python?
Pengujian kode yang dienkapsulasi melibatkan penulisan unit test untuk antarmuka publik suatu kelas. Dengan menguji metode dan property yang diekspos kepada pengguna, Anda memastikan perubahan keadaan internal dikelola dengan benar dan logika enkapsulasi tetap terjaga.
Apakah enkapsulasi dapat diterapkan pada modul Python, atau terbatas pada kelas?
Walaupun enkapsulasi terutama terkait dengan kelas, konsep ini dapat diperluas ke modul dengan menggunakan fungsi atau variabel yang diawali garis bawah untuk menandai penggunaan privat dalam modul.
Bagaimana hubungan enkapsulasi dengan polimorfisme di Python?
Enkapsulasi dan polimorfisme sama-sama prinsip OOP namun memiliki tujuan berbeda. Enkapsulasi membatasi akses ke bagian-bagian tertentu dari sebuah objek, sementara polimorfisme memungkinkan objek diperlakukan sebagai instance dari kelas induknya, sehingga memudahkan perluasan dan pemeliharaan kode. Keduanya dapat digunakan bersama untuk menciptakan struktur kode yang fleksibel dan aman.
Saya adalah kreator konten data science dengan pengalaman lebih dari 2 tahun dan salah satu dengan jumlah pengikut terbesar di Medium. Saya suka menulis artikel mendalam tentang AI dan ML dengan sedikit gaya sarkastik—karena harus ada sesuatu untuk membuatnya tidak terlalu membosankan. Saya telah menghasilkan lebih dari 130 artikel dan satu kursus di DataCamp, dengan satu lagi sedang dalam proses. Konten saya telah dilihat oleh lebih dari 5 juta pasang mata, dan 20 ribu di antaranya menjadi pengikut di Medium dan LinkedIn.

