Tujuan Praktikum
Setelah menyelesaikan praktikum ini, mahasiswa mampu:
- Menjelaskan konsep class dan object serta kaitannya dengan tabel database.
-
Membuat class
Produkbeserta atribut dan method-nya. - Membuat class
Pelanggan. -
Membuat class
TransaksidanItemTransaksiyang mewakili pola master–detail. - Mengubah baris database menjadi objek Python, dan sebaliknya.
Persiapan
Kebutuhan praktikum:
- VS Code
- Project toko-elektronik (dari Pertemuan 09)
- Database database/toko.db beserta isinya (dari Pertemuan 10)
- Virtual environment aktif (venv)
Buka project dan aktifkan venv:
venv\Scripts\activate
macOS / Linux: gunakan
source venv/bin/activate.
Pada pertemuan ini kita mengisi folder models/. Buat
tiga file kosong berikut di dalamnya:
models/
├── produk.py
├── pelanggan.py
└── transaksi.py
Konsep Singkat
Class dan Object
OOP (Object Oriented Programming) adalah cara menulis program dengan membungkus data dan perilaku menjadi satu kesatuan.
- Class adalah cetakan atau rancangan. Contoh: rancangan "Produk".
-
Object adalah wujud nyata dari
cetakan itu. Contoh: Laptop, Mouse, Keyboard — semuanya objek
dari class
Produk.
Analogi sederhana: class seperti cetakan kue, object adalah kue-kue yang dihasilkan dari cetakan tersebut. Satu cetakan, banyak kue.
Isi sebuah class:
- Atribut — datanya (nama produk, harga, stok).
- Method — perilakunya, yaitu fungsi milik class (menghitung nilai persediaan, mengurangi stok).
Hubungan dengan Database (Pertemuan 10)
Inilah kunci pertemuan ini. Class bukan hal baru yang terpisah — ia adalah perwakilan tabel di dalam kode Python:
| Database | Python |
|---|---|
Tabel produk |
Class Produk |
| Satu baris di tabel | Satu objek |
| Kolom (nama_produk, harga) |
Atribut (self.nama_produk,
self.harga)
|
Perhatikan juga: pola master–detail di database
(penjualan + detail_penjualan)
diterjemahkan menjadi
satu objek Transaksi yang memuat daftar objek
ItemTransaksi.
Mengapa Repot-repot Memakai Class?
Tanpa class, data produk berserakan dalam variabel terpisah. Dengan class, data dan perilakunya menyatu:
# tanpa class - data terpisah, perhitungan ditulis berulang
nama = "Laptop"
harga = 8500000
stok = 10
nilai = harga * stok
# dengan class - menyatu dan bisa dipakai ulang
laptop = Produk("Laptop", "Elektronik", 8500000, 10)
nilai = laptop.nilai_persediaan()
Langkah 1 - Class Produk
Buka models/produk.py, lalu tulis:
class Produk:
"""Mewakili satu baris pada tabel produk."""
def __init__(self, nama_produk, kategori, harga, stok=0, id_produk=None):
self.id_produk = id_produk
self.nama_produk = nama_produk
self.kategori = kategori
self.harga = harga
self.stok = stok
def nilai_persediaan(self):
return self.harga * self.stok
def __str__(self):
return f"{self.nama_produk} ({self.kategori}) - Rp {self.harga:,} | stok: {self.stok}"
Penjelasan bagian-bagiannya:
| Bagian | Arti |
|---|---|
class Produk: |
Mendefinisikan class (nama pakai PascalCase, ingat PEP8 di Pertemuan 09) |
__init__ |
Constructor — dijalankan otomatis saat objek dibuat |
self |
Menunjuk pada objek itu sendiri; selalu menjadi parameter pertama |
self.harga = harga |
Menyimpan nilai ke dalam atribut objek |
stok=0 |
Nilai bawaan bila tidak diisi |
id_produk=None |
Kosong dulu; diisi setelah data disimpan ke database |
__str__ |
Menentukan tampilan objek saat di-print()
|
Uji di main.py:
from models.produk import Produk
laptop = Produk("Laptop", "Elektronik", 8500000, 10)
mouse = Produk("Mouse", "Aksesoris", 150000, 50)
print(laptop)
print("Nilai persediaan:", f"Rp {laptop.nilai_persediaan():,}")
Output:
Laptop (Elektronik) - Rp 8,500,000 | stok: 10
Nilai persediaan: Rp 85,000,000
Satu class (Produk), dua objek (laptop,mouse). Masing-masing punya data sendiri, tetapi berbagi perilaku yang sama.
Langkah 2 - Menambah Method dan Validasi
Method membuat objek bisa "melakukan sesuatu". Tambahkan
method pengelolaan stok ke dalam class Produk:
def kurangi_stok(self, jumlah):
if jumlah <= 0:
raise ValueError("Jumlah harus lebih dari 0")
if jumlah > self.stok:
raise ValueError(f"Stok {self.nama_produk} tidak cukup (tersisa {self.stok})")
self.stok -= jumlah
return self.stok
def tambah_stok(self, jumlah):
self.stok += jumlah
return self.stok
Uji:
laptop = Produk("Laptop", "Elektronik", 8500000, 10)
laptop.kurangi_stok(3)
print("Stok sekarang:", laptop.stok)
try:
laptop.kurangi_stok(999) # sengaja melebihi stok
except ValueError as e:
print("Error:", e)
Output:
Stok sekarang: 7
Error: Stok Laptop tidak cukup (tersisa 7)
Inilah keunggulan OOP: aturan "stok tidak boleh minus" melekat pada classProduk. Di mana pun produk dipakai, aturan itu otomatis berlaku — tidak perlu ditulis ulang.raise ValueError(...)memunculkan error secara sengaja;try ... exceptmenangkapnya agar program tidak berhenti mendadak.
Langkah 3 - Class Pelanggan
Polanya sama, lebih sederhana. Buka
models/pelanggan.py:
class Pelanggan:
"""Mewakili satu baris pada tabel pelanggan."""
def __init__(self, nama, telepon="", alamat="", id_pelanggan=None):
self.id_pelanggan = id_pelanggan
self.nama = nama
self.telepon = telepon
self.alamat = alamat
def __str__(self):
return f"{self.nama} - {self.telepon} ({self.alamat})"
Uji:
from models.pelanggan import Pelanggan
budi = Pelanggan("Budi Santoso", "08123456789", "Jakarta")
print(budi)
Output:
Budi Santoso - 08123456789 (Jakarta)
Langkah 4 - Class Transaksi (Master-Detail)
Bagian terpenting. Ingat rancangan database: satu nota
(penjualan) memuat banyak barang
(detail_penjualan). Dalam OOP, ini menjadi
satu objek Transaksi yang menyimpan daftar objek
ItemTransaksi.
Buka models/transaksi.py:
class ItemTransaksi:
"""Satu baris barang di dalam nota (mewakili detail_penjualan)."""
def __init__(self, produk, qty):
self.produk = produk
self.qty = qty
def subtotal(self):
return self.produk.harga * self.qty
def __str__(self):
return f"{self.produk.nama_produk} x{self.qty} = Rp {self.subtotal():,}"
class Transaksi:
"""Mewakili satu nota (tabel penjualan) beserta isinya."""
def __init__(self, tanggal, pelanggan, id_penjualan=None):
self.id_penjualan = id_penjualan
self.tanggal = tanggal
self.pelanggan = pelanggan
self.items = [] # daftar ItemTransaksi
def tambah_item(self, produk, qty):
produk.kurangi_stok(qty) # stok otomatis berkurang
self.items.append(ItemTransaksi(produk, qty))
def total(self):
return sum(item.subtotal() for item in self.items)
def jumlah_barang(self):
return sum(item.qty for item in self.items)
def cetak_nota(self):
print("=" * 42)
print(f"NOTA PENJUALAN {self.tanggal}")
print(f"Pelanggan: {self.pelanggan.nama}")
print("-" * 42)
for item in self.items:
print(" ", item)
print("-" * 42)
print(f"TOTAL: Rp {self.total():,}")
print("=" * 42)
Perhatikan tiga hal penting:
-
self.items = []— sebuah objek dapat menyimpan daftar objek lain. Inilah wujud relasi master–detail dalam OOP. -
tambah_item()memanggilproduk.kurangi_stok(qty)— satu objek memakai method objek lain, sehingga stok terjaga otomatis. -
total()menjumlahkan seluruh subtotal — tidak perlu dihitung manual dari luar.
Uji di main.py:
from models.produk import Produk
from models.pelanggan import Pelanggan
from models.transaksi import Transaksi
laptop = Produk("Laptop", "Elektronik", 8500000, 10)
mouse = Produk("Mouse", "Aksesoris", 150000, 50)
budi = Pelanggan("Budi Santoso", "08123456789", "Jakarta")
trx = Transaksi("2025-03-01", budi)
trx.tambah_item(laptop, 1)
trx.tambah_item(mouse, 2)
trx.cetak_nota()
print("\nStok Laptop sekarang:", laptop.stok)
print("Stok Mouse sekarang :", mouse.stok)
Output:
==========================================
NOTA PENJUALAN 2025-03-01
Pelanggan: Budi Santoso
------------------------------------------
Laptop x1 = Rp 8,500,000
Mouse x2 = Rp 300,000
------------------------------------------
TOTAL: Rp 8,800,000
==========================================
Stok Laptop sekarang: 9
Stok Mouse sekarang : 48
Bandingkan dengan Pertemuan 10: totalnya
sama persis (Rp 8.800.000) dan stok Laptop juga
menjadi 9. Bedanya, di sini semuanya diurus oleh objek — kode di
main.py menjadi jauh lebih pendek dan mudah dibaca.
Langkah 5 - Menghubungkan Class dengan Database
Sekarang jembatannya: mengubah baris database menjadi objek, dan objek menjadi baris database. Pola inilah yang dipakai penuh pada CRUD (Pertemuan 12).
Buat file uji_db.py:
import sqlite3
from models.produk import Produk
conn = sqlite3.connect("database/toko.db")
cursor = conn.cursor()
# --- DARI DATABASE MENJADI OBJEK ---
cursor.execute("SELECT id_produk, nama_produk, kategori, harga, stok FROM produk")
baris_data = cursor.fetchall()
daftar_produk = []
for baris in baris_data:
p = Produk(
id_produk=baris[0],
nama_produk=baris[1],
kategori=baris[2],
harga=baris[3],
stok=baris[4],
)
daftar_produk.append(p)
print("Objek hasil dari database:")
for p in daftar_produk:
print(" -", p)
# setelah menjadi objek, method-nya bisa langsung dipakai
total_aset = sum(p.nilai_persediaan() for p in daftar_produk)
print("\nTotal nilai persediaan:", f"Rp {total_aset:,}")
# --- DARI OBJEK MENJADI BARIS DATABASE ---
speaker = Produk("Speaker", "Elektronik", 750000, 20)
cursor.execute(
"INSERT INTO produk (nama_produk, kategori, harga, stok) VALUES (?, ?, ?, ?)",
(speaker.nama_produk, speaker.kategori, speaker.harga, speaker.stok),
)
speaker.id_produk = cursor.lastrowid # objek kini punya id dari database
conn.commit()
print(f"\nProduk baru tersimpan dengan id: {speaker.id_produk}")
conn.close()
Output:
Objek hasil dari database:
- Laptop (Elektronik) - Rp 8,500,000 | stok: 10
- Monitor (Elektronik) - Rp 2,000,000 | stok: 15
- Mouse (Aksesoris) - Rp 150,000 | stok: 50
Total nilai persediaan: Rp 122,500,000
Produk baru tersimpan dengan id: 4
Inilah inti pertemuan ini. Database menyimpan data sebagai baris; Python mengolahnya sebagai objek. Menerjemahkan keduanya bolak-balik adalah pekerjaan sehari-hari pengembang aplikasi — dan itulah yang akan kita rapikan menjadi CRUD pada Pertemuan 12.
Referensi Fungsi Penting
Anatomi Class
| Elemen | Penulisan | Fungsi |
|---|---|---|
| Definisi class | class Produk: |
Membuat cetakan (PascalCase) |
| Constructor | def __init__(self, ...): |
Dijalankan saat objek dibuat |
| Atribut | self.harga = harga |
Menyimpan data objek |
| Method | def nilai_persediaan(self): |
Perilaku objek |
| Tampilan | def __str__(self): |
Hasil saat objek di-print() |
| Membuat objek | p = Produk("Laptop", ...) |
Mewujudkan class |
| Memanggil method | p.nilai_persediaan() |
Menjalankan perilaku |
| Mengakses atribut | p.harga |
Membaca data objek |
Penanganan Error
| Perintah | Fungsi |
|---|---|
raise ValueError("pesan") |
Memunculkan error secara sengaja |
try: ... except ValueError as e: |
Menangkap error agar program tetap berjalan |
Pola Baris Database → Objek
cursor.execute("SELECT id_produk, nama_produk, kategori, harga, stok FROM produk")
daftar = [
Produk(id_produk=b[0], nama_produk=b[1], kategori=b[2], harga=b[3], stok=b[4])
for b in cursor.fetchall()
]
Ingin Mendalami OOP?
Pertemuan ini membahas fondasi OOP secukupnya untuk membangun aplikasi penjualan: class, object, atribut, dan method. Sesungguhnya OOP memiliki empat pilar yang lebih luas:
| Pilar | Inti |
|---|---|
| Encapsulation | Melindungi data agar tidak diubah sembarangan |
| Inheritance | Membuat class baru dengan mewarisi class lain |
| Polymorphism | Satu perintah, perilaku berbeda pada tiap objek |
| Abstraction | Kontrak yang wajib dipenuhi class turunan |
Keempatnya tidak diperlukan untuk menyelesaikan aplikasi kita (Pertemuan 12–16), sehingga tidak dibahas di sini agar praktikum tetap fokus.
Bagi yang ingin memahami OOP secara utuh, tersedia materi tambahan Bonus Materi - OOP Lanjutan (opsional, bernilai tambahan).
Pengujian
Pastikan hasil praktikum sesuai berikut:
-
File
models/produk.py,models/pelanggan.py, danmodels/transaksi.pyterisi. -
print(laptop)menampilkanLaptop (Elektronik) - Rp 8,500,000 | stok: 10. -
laptop.nilai_persediaan()menghasilkan 85.000.000. -
kurangi_stok()dengan jumlah melebihi stok memunculkan pesan error, bukan stok minus. -
trx.cetak_nota()menampilkan TOTAL: Rp 8.800.000 (Laptop 1 + Mouse 2). - Stok berkurang otomatis setelah transaksi: Laptop 10 → 9, Mouse 50 → 48.
Verifikasi cepat:
laptop = Produk("Laptop", "Elektronik", 8500000, 10)
mouse = Produk("Mouse", "Aksesoris", 150000, 50)
budi = Pelanggan("Budi Santoso")
trx = Transaksi("2025-03-01", budi)
trx.tambah_item(laptop, 1)
trx.tambah_item(mouse, 2)
assert trx.total() == 8800000
assert trx.jumlah_barang() == 3
assert laptop.stok == 9 and mouse.stok == 48
print("Semua pengujian lolos.")
Troubleshooting
| Masalah | Penyebab | Solusi |
|---|---|---|
ModuleNotFoundError: No module named
'models'
|
Program dijalankan dari folder yang salah |
Jalankan python main.py dari folder utama
project
|
TypeError: __init__() missing argument |
Ada parameter wajib yang tidak diisi | Lengkapi argumen saat membuat objek |
AttributeError: object has no attribute |
Nama atribut salah ketik | Cocokkan dengan yang ditulis di __init__ |
| Method dipanggil tanpa hasil | Lupa tanda kurung |
Tulis p.nilai_persediaan(), bukan
p.nilai_persediaan
|
print(objek) menampilkan
<object at 0x...>
|
Class belum punya __str__ |
Tambahkan method __str__ |
Lupa menulis self |
Parameter pertama method wajib self |
def nilai_persediaan(self): |
Tugas Praktikum
Kembangkan class yang sudah dibuat:
-
Tambahkan method
diskon(self, persen)pada classProdukyang mengembalikan harga setelah diskon (tanpa mengubah harga aslinya). -
Tambahkan method
is_stok_menipis(self)pada classProdukyang mengembalikanTruebila stok kurang dari 5. -
Tambahkan method
jumlah_item(self)pada classTransaksiyang mengembalikan banyaknya jenis barang dalam nota (berbeda denganjumlah_barang()yang menghitung total unit). - Buat satu transaksi baru berisi 3 jenis produk berbeda, cetak notanya, lalu tampilkan stok akhir tiap produk.
- Buat program yang membaca seluruh produk dari database, mengubahnya menjadi objek, lalu menampilkan produk yang stoknya menipis (memakai method dari nomor 2).
Kumpulkan berupa file .py beserta tangkapan layar
hasil menjalankannya (format PDF).
Kesimpulan
Pada pertemuan ini mahasiswa mempelajari
OOP bukan sebagai teori terpisah, melainkan
sebagai cara Python mewakili tabel database: satu
tabel menjadi satu class, satu baris menjadi satu objek, dan kolom
menjadi atribut. Class Produk dibekali method yang
menjaga aturan (stok tidak boleh minus), sementara class
Transaksi dan
ItemTransaksi menerjemahkan pola
master–detail menjadi objek yang memuat daftar
objek lain. Mahasiswa juga berlatih mengubah baris database
menjadi objek dan sebaliknya. Pada pertemuan berikutnya, pola
tersebut dirapikan menjadi operasi CRUD (Create,
Read, Update, Delete) yang lengkap untuk data produk.