Object-Oriented Python untuk Pemula: Class, Object, dan Dataclass
Object-oriented programming atau OOP sering terdengar besar dan akademis. Padahal dalam praktik Python, OOP bisa dipahami dengan sederhana: object adalah data yang dibungkus bersama behavior yang relevan.
Kamu tidak harus memakai class untuk semua hal. Banyak kode Python tetap lebih enak ditulis dengan function biasa. Tapi saat data dan behavior mulai sering jalan bareng, class bisa membuat kode lebih rapi.
Gunakan OOP untuk memperjelas batas sebuah konsep, bukan sekadar supaya kode terlihat lebih profesional. Sebelum membuat class, tanyakan: apakah object ini punya identitas, data yang bertahan, dan operasi yang selalu berkaitan dengan data tersebut? Jika tidak, function dan dictionary mungkin sudah cukup.
Object sebagai data plus behavior
Bayangkan expense dalam aplikasi pencatat pengeluaran. Expense punya data:
- title
- amount
- category
Expense juga bisa punya behavior:
- mengecek apakah pengeluaran besar
- memformat amount
- mengubah data menjadi dictionary
Kalau data dan behavior itu selalu dipakai bersama, object bisa membantu.
Object juga membantu menjaga aturan. Misalnya, BankAccount dapat memastikan saldo tidak berkurang melebihi batas yang diizinkan. Aturan itu diletakkan dekat dengan data yang dijaganya, sehingga caller tidak perlu mengulang validasi di banyak tempat.
Membuat class sederhana
Class adalah blueprint. Object adalah hasil nyata dari blueprint itu.
# File: 01-class-object.py
class Expense:
pass
expense = Expense()
print(expense)
Kode di atas membuat class kosong. Belum berguna, tapi menunjukkan bentuk paling dasar.
init dan instance attribute
Method __init__ berjalan saat object dibuat. Kita bisa memakainya untuk menerima data awal.
# File: 02-user-class.py
class Expense:
def __init__(self, title, amount):
self.title = title
self.amount = amount
expense = Expense("Keyboard", 350_000)
print(expense.title)
print(expense.amount)
self merujuk ke object yang sedang dibuat atau sedang memakai method. self.title dan self.amount disebut instance attribute karena nilainya melekat pada instance tertentu.
Method
Method adalah function yang hidup di dalam class.
# File: 03-init-attribute.py
class Expense:
def __init__(self, title, amount):
self.title = title
self.amount = amount
def is_large(self):
return self.amount >= 100_000
expense = Expense("Keyboard", 350_000)
print(expense.is_large())
is_large() bisa mengakses self.amount karena method itu milik object expense.
Class vs instance
Class adalah blueprint:
# File: 04-method.py
class User:
pass
Instance adalah object yang dibuat dari class:
# File: 05-class-vs-instance.py
user_a = User()
user_b = User()
Setiap instance bisa punya data berbeda.
# File: 06-dataclass.py
class User:
def __init__(self, name):
self.name = name
user_a = User("Ayu")
user_b = User("Budi")
print(user_a.name)
print(user_b.name)
Pahami perbedaan ini dulu sebelum masuk ke konsep yang lebih jauh seperti inheritance.
Dataclass untuk object data
Kalau class kamu terutama berisi data, dataclass membuat kode lebih ringkas.
# File: 07-bank-account.py
from dataclasses import dataclass
@dataclass
class Expense:
title: str
amount: int
def is_large(self):
return self.amount >= 100_000
expense = Expense("Keyboard", 350_000)
print(expense.is_large())
print(expense)
Dengan dataclass, Python otomatis membuat __init__ dan representasi object yang lebih nyaman dibaca.
Gunakan dataclass saat object terutama berfungsi sebagai wadah data. Jika ada aturan validasi atau perubahan state yang harus selalu dijaga, tambahkan method seperti is_large() atau gunakan class biasa agar behavior tetap dekat dengan data.
Contoh: BankAccount
Class berguna saat ada aturan yang perlu menjaga data.
# File: 08-composition.py
class BankAccount:
def __init__(self, owner, balance=0):
self.owner = owner
self.balance = balance
def deposit(self, amount):
if amount <= 0:
raise ValueError("Amount must be positive")
self.balance += amount
def withdraw(self, amount):
if amount > self.balance:
raise ValueError("Insufficient balance")
self.balance -= amount
account = BankAccount("Ayu")
account.deposit(100_000)
account.withdraw(40_000)
print(account.balance)
Tanpa class, owner, balance, dan aturan deposit/withdraw bisa tersebar di banyak function. Dengan class, aturan itu berada dekat dengan data yang dijaga.
Perhatikan bahwa method deposit() memvalidasi amount sebelum mengubah balance. Ini contoh encapsulation sederhana: caller tidak perlu tahu detail perubahan saldo, cukup memanggil operasi yang tersedia dan menangani error jika aturan dilanggar.
Composition dibanding inheritance
Pemula sering terlalu cepat belajar inheritance. Inheritance memang berguna, tapi tidak selalu pilihan pertama.
Composition berarti sebuah object menyimpan object lain.
# File: 09-inheritance-overuse.py
from dataclasses import dataclass
@dataclass
class Customer:
name: str
email: str
@dataclass
class Order:
customer: Customer
total: int
customer = Customer("Ayu", "[email protected]")
order = Order(customer, 250_000)
print(order.customer.email)
Untuk banyak kasus aplikasi sehari-hari, composition lebih mudah dipahami daripada inheritance bertingkat.
Contohnya, Order memiliki Customer; order bukan customer. Ini hubungan “has-a”, sehingga composition lebih cocok. Inheritance lebih tepat saat subclass benar-benar merupakan bentuk khusus dari parent dan dapat dipakai di tempat yang sama tanpa perilaku mengejutkan.
Kapan OOP membantu?
OOP biasanya membantu ketika:
- Data dan behavior sering dipakai bersama.
- Ada aturan yang perlu menjaga perubahan data.
- Kamu punya beberapa object dengan bentuk sama.
- Kode function mulai sering mengoper dictionary besar ke banyak tempat.
Contoh yang cocok: user, order, invoice, bank account, task, expense, product, atau game character.
Kapan function biasa cukup?
Function biasa sering cukup ketika:
- Logic-nya kecil.
- Data tidak punya behavior khusus.
- Kamu hanya melakukan transformasi sederhana.
- Class hanya akan berisi satu method.
Contoh:
# File: 10-function-enough.py
def calculate_total(prices):
return sum(prices)
Tidak perlu membuat class hanya untuk function sesederhana ini.
Kesalahan umum
Kesalahan pertama adalah membuat class terlalu besar. Jika class punya banyak tanggung jawab, pecah menjadi class atau function yang lebih kecil.
Kesalahan kedua adalah memakai inheritance terlalu dini. Mulai dari composition dan function sederhana dulu.
Kesalahan ketiga adalah shared mutable state di level class.
# File: 11-class-mistake.py
class Cart:
items = []
items di atas dibagi oleh semua instance. Lebih aman taruh di __init__:
# File: 12-private-state.py
class Cart:
def __init__(self):
self.items = []
Latihan mini
Coba buat:
- Class
Taskdengantitle,done, dan methodmark_done(). - Dataclass
Productdenganname,price, dan methodis_expensive(). - Class
BankAccountdengan deposit dan withdraw. - Class
Orderyang menyimpan beberapa item dan menghitung total. - Versi function biasa dari salah satu contoh, lalu bandingkan mana yang lebih enak dibaca.
Checklist sebelum lanjut
Sebelum membuat class, coba tulis versi function dan dictionary terlebih dahulu. Jika versi itu masih pendek dan jelas, class belum tentu memberi manfaat. Jika aturan validasi mulai tersebar atau beberapa function selalu menerima data yang sama, itulah sinyal bahwa object mungkin membantu.
Setelah membuat class, uji state awal, operasi yang valid, dan operasi yang harus ditolak. Class yang baik bukan hanya punya banyak method; ia membuat aturan domain lebih mudah ditemukan dan lebih sulit dilanggar secara tidak sengaja.
Lanjut ke project structure
Setelah memahami OOP, langkah berikutnya adalah menyusun project Python yang lebih rapi: folder, virtual environment, dependency, dan testing. Lanjut ke Python Project Structure: venv, pip, Requirements, dan Testing.
Kalau ingin mengulang bagian sebelumnya, baca Python Files, Errors, dan Modules.
Artikel Terkait
Lanjutkan membaca topik yang masih satu konteks.
Jalur Belajar Python Fundamental: Rangkuman Seri dan Langkah Lanjut
Rangkuman praktis seri Python Fundamental berisi enam materi, skill utama, checkpoint latihan, dan langkah lanjut setelah membuat project CLI.
Mini Project Python: Build CLI Expense Tracker dari Nol
Bangun CLI expense tracker dengan Python dari nol memakai input, JSON file storage, function, dataclass, error handling, dan testing dasar.
Python Project Structure: venv, pip, Requirements, dan Testing
Belajar menyusun project Python yang rapi dengan struktur folder, virtual environment, pip, requirements.txt, .env, pytest, dan entry point sederhana.
Python Files, Errors, dan Modules: Membuat Script yang Lebih Rapi
Belajar membaca file, menulis file, menangani error, membuat module, import kode sendiri, dan menyusun script Python yang lebih rapi.