Python

Panduan Belajar Python: Object-Oriented Programming (OOP) di Python

Panduan ini untuk siapa

  • Pembelajar yang sudah memahami fundamental Python dan function
  • Developer yang ingin memodelkan entitas dunia nyata dengan struktur yang bersih
  • Siapa pun yang bersiap membangun aplikasi lebih besar dengan komponen reusable

Apa yang akan Anda pelajari

  • Cara kerja class dan object di Python
  • Peran __init__ dan jenis method yang berbeda (instance, class, static)
  • Bagaimana inheritance, encapsulation, dan polymorphism meningkatkan desain
  • Kapan dan mengapa memakai abstract base classes (abc)
  • Kesalahan OOP umum dan cara menghindari overengineering

Mengapa topik ini penting

Saat project bertambah besar, script biasa menjadi sulit dirawat. OOP membantu Anda mengorganisasi data dan perilaku ke unit yang jelas (class) sehingga kode lebih mudah dibaca, diuji, dan dikembangkan.

Di Python, OOP bersifat praktis, bukan kaku. Anda bisa menggabungkan desain berorientasi objek dengan pola fungsional, lalu memilih struktur paling sederhana yang cocok dengan masalah Anda. Menguasai OOP memberi fondasi kuat untuk framework, API, dan codebase yang scalable.

Konsep inti

Classes, objects, dan constructor

Class adalah blueprint; object adalah instance dari blueprint tersebut.

class User:
	def __init__(self, username, email):
		self.username = username
		self.email = email

	def profile(self):
		return f"{self.username} <{self.email}>"


user = User("katie", "[email protected]")
print(user.profile())

Expected output:

katie <[email protected]>

__init__ dijalankan ketika object baru dibuat. Method ini menginisialisasi state object.

Jenis method dan encapsulation

Class Python umumnya memakai tiga jenis method:

  • Instance methods: beroperasi pada data object (self)
  • Class methods: beroperasi pada konteks level class (cls)
  • Static methods: logika utilitas terkait domain class tetapi tanpa state instance/class
class Temperature:
	scale = "Celsius"

	def __init__(self, celsius):
		self._celsius = celsius

	def to_fahrenheit(self):
		return (self._celsius * 9 / 5) + 32

	@classmethod
	def from_fahrenheit(cls, fahrenheit):
		celsius = (fahrenheit - 32) * 5 / 9
		return cls(celsius)

	@staticmethod
	def is_valid(value):
		return isinstance(value, (int, float))

Gaya penamaan _celsius menandakan atribut internal (encapsulation berbasis konvensi).

Konvensi visibilitas encapsulation di Python:

  • Public attribute: name (ditujukan untuk akses eksternal normal)
  • Protected-style attribute: _balance (konvensi: penggunaan internal)
  • Private-style attribute: __pin (name-mangled untuk mengurangi akses tidak sengaja)
class Wallet:
	def __init__(self, owner, pin):
		self.owner = owner          # public
		self._balance = 0           # protected-style
		self.__pin = pin            # private-style

	def deposit(self, amount):
		self._balance += amount

	def check_pin(self, pin):
		return self.__pin == pin


w = Wallet("Ava", "1234")
w.deposit(100)
print(w.owner)            # public access
print(w._balance)         # possible, but convention says internal
print(w.check_pin("1234"))

Inheritance, polymorphism, dan abstract base classes

Inheritance memungkinkan child class memakai ulang dan memperluas behavior parent. Polymorphism memungkinkan class berbeda berbagi interface yang sama.

Bentuk inheritance yang umum:

  • Single inheritance: satu child mewarisi satu parent
  • Multiple inheritance: satu child mewarisi banyak parent
  • Multilevel inheritance: rantai class (Grandparent -> Parent -> Child)

Contoh tipe inheritance:

# Single inheritance
class Animal:
	def speak(self):
		return "..."


class Dog(Animal):
	def speak(self):
		return "Woof"


# Multiple inheritance
class FlyMixin:
	def fly(self):
		return "Flying"


class SwimMixin:
	def swim(self):
		return "Swimming"


class Duck(FlyMixin, SwimMixin):
	pass


# Multilevel inheritance
class Vehicle:
	def category(self):
		return "Transport"


class Car(Vehicle):
	def wheels(self):
		return 4


class ElectricCar(Car):
	def power_source(self):
		return "Battery"


print(Dog().speak())
print(Duck().fly(), Duck().swim())
print(ElectricCar().category(), ElectricCar().wheels(), ElectricCar().power_source())
from abc import ABC, abstractmethod


class PaymentProcessor(ABC):
	@abstractmethod
	def pay(self, amount):
		pass


class CardPayment(PaymentProcessor):
	def pay(self, amount):
		return f"Paid ${amount} by card"


class WalletPayment(PaymentProcessor):
	def pay(self, amount):
		return f"Paid ${amount} by wallet"


def checkout(processor, amount):
	print(processor.pay(amount))


checkout(CardPayment(), 120)
checkout(WalletPayment(), 85)

Expected output:

Paid $120 by card
Paid $85 by wallet

Pola ini memudahkan extension sambil menjaga API tetap konsisten.

Sketsa UML sederhana (berbasis teks):

PaymentProcessor (abstract)
├── CardPayment
└── WalletPayment

Diagram class seperti ini membantu mendokumentasikan relasi untuk rekan tim sebelum implementasi.

Panduan langkah demi langkah

Langkah 1 — Buat model class sederhana

Mulai dengan satu class yang memiliki data dan behavior sekaligus.

class BankAccount:
	def __init__(self, owner, balance=0):
		self.owner = owner
		self.balance = balance

	def deposit(self, amount):
		self.balance += amount

	def withdraw(self, amount):
		if amount > self.balance:
			raise ValueError("Insufficient balance")
		self.balance -= amount

Ini memberi Anda unit yang bersih dengan tanggung jawab jelas.

Langkah 2 — Tambahkan inheritance untuk behavior khusus

Buat subclass untuk savings account dengan aturan tambahan.

class SavingsAccount(BankAccount):
	def __init__(self, owner, balance=0, interest_rate=0.03):
		super().__init__(owner, balance)
		self.interest_rate = interest_rate

	def apply_interest(self):
		self.balance += self.balance * self.interest_rate

Gunakan super() untuk memakai ulang inisialisasi parent dengan bersih.

Langkah 3 — Perkenalkan interface polymorphic

Rancang kode yang bisa bekerja dengan class apa pun yang mengimplementasikan method yang sama.

class EmailNotifier:
	def send(self, message):
		print(f"Email: {message}")


class SMSNotifier:
	def send(self, message):
		print(f"SMS: {message}")


def notify_all(notifiers, message):
	for notifier in notifiers:
		notifier.send(message)


notify_all([EmailNotifier(), SMSNotifier()], "Payment received")

Ini menjaga business logic tetap fleksibel tanpa rantai if/elif untuk setiap tipe.

Contoh praktis

Contoh 1 — Model inventory product

Memodelkan product sebagai object membuat update state lebih jelas.

class Product:
	def __init__(self, name, price, stock):
		self.name = name
		self.price = price
		self.stock = stock

	def sell(self, quantity):
		if quantity > self.stock:
			raise ValueError("Not enough stock")
		self.stock -= quantity

	def __str__(self):
		return f"{self.name} | ${self.price} | stock={self.stock}"


laptop = Product("Laptop", 999, 5)
laptop.sell(2)
print(laptop)

Expected output:

Laptop | $999 | stock=3

Contoh 2 — Abstract report exporters

Gunakan abstract base classes untuk menegakkan method yang wajib.

from abc import ABC, abstractmethod


class ReportExporter(ABC):
	@abstractmethod
	def export(self, data):
		pass


class CSVExporter(ReportExporter):
	def export(self, data):
		return f"CSV export: {data}"


class JSONExporter(ReportExporter):
	def export(self, data):
		return f"JSON export: {data}"


for exporter in [CSVExporter(), JSONExporter()]:
	print(exporter.export({"users": 120}))

Expected output:

CSV export: {'users': 120}
JSON export: {'users': 120}

Pola ini berguna saat Anda mendukung banyak format output atau backend.

Kesalahan umum dan cara menghindarinya

  • Mengubah semua script menjadi class terlalu cepat -> Mulai sederhana; perkenalkan class saat state + behavior memang cocok digabung.
  • Mengekspos internal mutable secara sembarangan -> Gunakan method yang jelas (deposit, withdraw) alih-alih perubahan langsung tanpa kontrol.
  • Rantai inheritance terlalu dalam -> Pilih composition saat inheritance mulai sulit dipahami.
  • Mengabaikan konsistensi interface -> Jaga nama/parameter method tetap prediktif pada class yang saling terkait.
  • Melupakan single responsibility -> Satu class sebaiknya mengerjakan satu tugas inti dengan baik.

Latihan cepat

  • Bangun class Student dengan atribut (name, scores) dan method (add_score, average_score).
  • Buat parent class Animal dengan subclass Dog dan Cat, masing-masing mengimplementasikan method speak().
  • Definisikan abstract class Storage lalu implementasikan LocalStorage + CloudStorage dengan interface save(data) yang sama.

Ringkasan utama

  • OOP membantu menstrukturkan program Python yang lebih besar melalui komponen reusable dan testable.
  • __init__, jenis method, dan konvensi encapsulation adalah alat inti harian.
  • Inheritance dan polymorphism meningkatkan extensibility jika dipakai secara terukur.
  • Abstract base classes membantu menegakkan kontrak pada desain multi-implementasi.

Langkah berikutnya

Lanjut ke [07. Dasar Struktur Data & Algoritma](./07-data-structures-and-algorithms-basics-ID.md). Di panduan berikutnya, Anda akan meninjau struktur inti, cara berpikir kompleksitas, dan pola sorting/searching penting yang dipakai di interview dan sistem nyata.

No Comments

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.