Pemrograman Berorientasi Objek di Python

Pengertian Pemrograman Berorientasi Objek

Pemrograman berorientasi objek atau dalam bahasa inggris disebut Object Oriented Programming (OOP) adalah paradigma atau teknik pemrograman di mana semua hal dalam program dimodelkan seperti objek dalam dunia nyata. Objek di dunia nyata memiliki ciri atau attribut dan juga aksi atau kelakuan (behaviour).

Kita misalkan sebuah mobil. Mobil memiliki ciri punya ban, stang, kursi, pedal gas, rem, dan lain sebagainya. Ada juga ciri warna, atau tahun keluaran berapa. Selain punya ciri, mobil juga punya aksi atau sesuatu yang bisa dilakukan olehnya. Misalnya, ketika pedal diinjak apa yang terjadi. Ketika di rem apa yang terjadi, dan lain sebagainya.

Program juga demikian. Semua unit dalam program bisa dianggap sebagai objek. Objek besar dibangun dari objek – objek yang lebih kecil. Objek yang satu berinteraksi dengan objek yang lain, sehingga semua menjadi sebuah kesatuan yang utuh.

Python dari awal dibuat sudah mengadopsi OOP. Selain itu Python juga bisa menggunakan paradigma pemrograman lama yaitu pemrograman terstruktur. Oleh karena itu, Python disebut bersifat hibrid.


Istilah – Istilah Dalam OOP

Sebelum mempelajari lebih jauh tentang OOP, ada baiknya kita harus mengetahui istilah – istilah dalam OOP, yaitu sebagai berikut:

  • Kelas – Kelas adalah cetak biru atau prototipe dari objek dimana kita mendefinisikan atribut dari suatu objek. Atribut ini terdiri dari data member (variabel) dan fungsi (metode).
  • Variabel Kelas – Variabel kelas adalah variabel yang dishare atau dibagi oleh semua instance (turunan) dari kelas. Variabel kelas didefinisikan di dalam kelas, tapi di luar metode-metode yang ada dalam kelas tersebut.
  • Data member – Data member adalah variabel yang menyimpan data yang berhubungan dengan kelas dan objeknya
  • Overloading Fungsi – Overloading fungsi adalah fungsi yang memiliki nama yang sama di dalam kelas, tapi dengan jumlah dan tipe argumen yang berbeda sehingga dapat melakukan beberapa hal yang berbeda.
  • Overloading operator – Overloading operator adalah pembuatan beberapa fungsi atau kegunaan untuk suatu operator. Misalnya operator + dibuat tidak hanya untuk penjumlahan, tapi juga untuk fungsi lain.
  • Variabel instansiasi – Variabel instansiasi adalah variabel yang didefinisikan di dalam suatu metode dan hanya menjadi milik dari instance kelas.
  • Pewarisan/Inheritansi – Inheritansi adalah pewarisan karakteristik sebuah kelas ke kelas lain yang menjadi turunannya.
  • InstanceInstance adalah istilah lain dari objek suatu kelas. Sebuah objek yang dibuat dari prototipe kelas Lingkaran misalnya disebut sebagai instance dari kelas tersebut.
  • Instansiasi – Instansiasi adalah pembuatan instance/objek dari suatu kelas
  • Metode – Metode adalah fungsi yang didefinisikan di dalam suatu kelas
  • Objek – Objek adalah instansiasi atau perwujudan dari sebuah kelas. Bila kelas adalah prototipenya, dan objek adalah barang jadinya.

Pembuatan Kelas

Kita mendefinisikan sebuah kelas dengan menggunakan kata kunci class diikuti oleh nama kelas tersebut. Berikut adalah sintaks pembuatan kelas di Python.

class ClassName:
    '''class docstring'''
    class_body

Kelas memiliki docstring atau string dokumentasi yang bersifat opsional artinya bisa ada atau tidak. Docstring bisa diakses menggunakan format ClassName.__doc__

class_body terdiri dari semua pernyataan berupa attribut, fungsi, dan data dari kelas


Contoh Kelas

Berikut adalah contoh kelas yang sederhana:

class Karyawan:
    '''Dasar kelas untuk semua karyawan'''
    jumlah_karyawan = 0

    def __init__(self, nama, gaji):
        self.nama = nama
        self.gaji = gaji
        Karyawan.jumlah_karyawan += 1

    def tampilkan_jumlah(self):
        print("Total karyawan:", Karyawan.jumlah_karyawan)

    def tampilkan_profil(self):
        print("Nama :", self.nama)
        print("Gaji :", self.gaji)
        print()

Variabel jumlah_karyawan adalah variabel kelas yang dibagi ke semua instance/objek dari kelas ini. Variabel ini bisa diakses dari dalam atau luar kelas dengan menggunakan notasi titik, Karyawan.jumlah_karyawan.

Metode __init__() adalah metode konstruktor, yaitu metode khusus yang digunakan Python untuk menginisialisasi pembuatan objek dari kelas tersebut.

Fungsi – fungsi di dalam kelas (disebut metode) pendefinisiannya sama dengan fungsi pada umumnya. Hanya saja, harus ada argumen pertama bernama self. Pada saat pemanggilan fungsi, argumen ini otomatis ditambahkan oleh Python. Anda tidak perlu menambahkannya pada saat memanggil fungsi.


Instansiasi Objek

Untuk membuat objek dari sebuah kelas, kita bisa memanggil nama kelas dengan argumen sesuai dengan fungsi __init__() pada saat kita mendefinisikannya.

# Membuat objek pertama dari kelas Karyawan
karyawan1 = Karyawan("Sarah", 1000000)

# Membuat objek kedua dari kelas Karyawan
karyawan2 = Karyawan("Budi", 2000000)

Mengakses Attribut Objek

Kita bisa mengakses atribut objek dengan menggunakan operator titik. Variabel kelas bisa diakses dengan menggunakan nama kelasnya.

karyawan1.tampilkan_profil()
karyawan2.tampilkan_profil()
print("Total karyawan :", Karyawan.jumlah_karyawan)

Sekarang, mari kita gabungkan semua contoh di atas.

class Karyawan: '''Dasar kelas untuk semua karyawan''' jumlah_karyawan = 0 def __init__(self, nama, gaji): self.nama = nama self.gaji = gaji Karyawan.jumlah_karyawan += 1 def tampilkan_jumlah(self): print("Total karyawan:", Karyawan.jumlah_karyawan) def tampilkan_profil(self): print("Nama :", self.nama) print("Gaji :", self.gaji) # Membuat objek pertama dari kelas Karyawan karyawan1 = Karyawan("Sarah", 1000000) # Membuat objek kedua dari kelas Karyawan karyawan2 = Karyawan("Budi", 2000000) karyawan1.tampilkan_profil() karyawan2.tampilkan_profil() print("Total karyawan :", Karyawan.jumlah_karyawan)

Pada saat program di atas dijalankan, outputnya adalah seperti berikut:

Nama : Sarah
Gaji : 1000000
Nama : Budi
Gaji : 2000000
Total karyawan : 2

Menambah, Menghapus, dan Mengubah Atribut Objek

Kita bisa menambah, menghapus, dan mengubah atribut objek seperti berikut:

karyawan1.gaji = 1500000
karyawan1.nama = 'Ratna'
del karyawan1.gaji

Cara yang lebih elegan untuk memodifikasi atribut adalah dengan menggunakan fungsi – fungsi berikut:

  • getattr(obj, name[, default]) – Mengakses atribut objek
  • hasattr(obj, name) – Memeriksa apakah objek memiliki atribut tertentu atau tidak
  • setattr(obj, name, value) – Mengatur nilai atribut. Jika atribut tidak ada, maka atribut tersebut akan dibuatkan
  • delattr(obj, name) – Menghapus atribut dari objek
hasattr(karyawan1, 'gaji')    # True jika atribut 'gaji' ada
getattr(karyawan1, 'gaji')   # mengembalikan nilai dari attribut 'gaji'
setattr(karyawan1, 'gaji', 1600000)  # mengatur nilai atribut 'gaji'
delattr(karyawan1, 'gaji') # menghapus atribut 'gaji'

Atribut Kelas Built-in

Setiap kelas di Python memiliki atribut built-in (bawaan) yang bisa diakses menggunakan operator titik. Attribut-attribut tersebut adalah sebagai berikut:

  • __dict__ – dictionary yang berisi namespace dari kelas
  • __doc__ – mengakses string dokumentasi (docstring) dari kelas
  • __name__ – nama kelas
  • __module__ – nama modul tempat kelas didefinisikan. Nilai attribut ini di mode interaktif adalah “__main__“.
  • __bases__ – dasar dari kelas, bila kelas tidak merupakan turunan dari kelas lain, maka induknya dalah kelas object.
class Karyawan: '''Dasar kelas untuk semua karyawan''' jumlah_karyawan = 0 def __init__(self, nama, gaji): self.nama = nama self.gaji = gaji Karyawan.jumlah_karyawan += 1 def tampilkan_jumlah(self): print("Total karyawan:", Karyawan.jumlah_karyawan) def tampilkan_profil(self): print("Nama :", self.nama) print("Gaji :", self.gaji) # Membuat objek pertama dari kelas Karyawan karyawan1 = Karyawan("Sarah", 1000000) # Membuat objek kedua dari kelas Karyawan karyawan2 = Karyawan("Budi", 2000000) print("Karyawan.__doc__:", Karyawan.__doc__) print("Karyawan.__name__:", Karyawan.__name__) print("Karyawan.__module__:", Karyawan.__module__) print("Karyawan.__dict__:", Karyawan.__dict__) print("Karyawan.__bases__:", Karyawan.__bases__)

Output dari program di atas adalah:

Karyawan.__doc__: Dasar kelas untuk semua karyawan
Karyawan.__name__: Karyawan
Karyawan.__module__: __main__
Karyawan.__dict__: {'tampilkan_jumlah': , '__module__': '__main__', '__doc__': 'Dasar kelas untuk semua karyawan', 'jumlah_karyawan': 2, '__weakref__': <attribute '__weakref__' of 'Karyawan' objects>, 'tampilkan_profil': , '__dict__': <attribute '__dict__' of 'Karyawan' objects>, '__init__': }
Karyawan.__bases__: (<class 'object'>,)

Penghancuran Objek (Pengumpulan Sampah/Garbage Collection)

Python menghapus objek yang sudah tidak terpakai secara otomatis untuk menghemat memori. Proses ini disebut dengan pengumpulan sampah (garbage collection).

Kolektor sampah Python terus berjalan pada saat program dieksekusi dan dipicu pada saat tidak ada lagi referensi/variabel yang merujuk ke objek.

Jumlah referensi terhadap objek bertambah pada saat ada variabel yang merujuk ke objek tersebut. Sebaliknya referensi terhadap objek berkurang ketika variabel terhapus dengan menggunakan del, atau saat terjadi penugasan ulang, atau saat referensi keluar dari scope-nya.

Pada saat referensi terhadap objek sudah nol, maka Python akan otomatis menghapus objek tersebut. Perhatikan contoh berikut:

a = 30    # Menciptakan objek <30>
b = a     # menambah jumlah referensi ke objek <30>
c = [b]   # menambah jumlah referensi ke objek <30>

del a     # mengurangi jumlah referensi ke objek <30>
b = 100   # mengurangi jumlah referensi ke objek <30>
c[0] = -1 # mengurangi jumlah referensi ke objek <30>

Pada contoh di atas, objek 30 pada akhirnya akan dihapus karena sudah tidak ada variabel yang merujuk ke objek tersebut.

Python melakukan penghapusan objek secara otomatis tanpa ada pemberitahuan. Kita bisa menggunakan sebuah metode khusus yaitu metode __del__() yang disebut destruktor, yang akan dipanggil apabila sebuah objek akan dihapuskan oleh python.

Berikut adalah contoh penggunaan destruktor __del__().

class Point: def __init__( self, x=0, y=0): self.x = x self.y = y def __del__(self): class_name = self.__class__.__name__ print (class_name, "dihancurkan") pt1 = Point() pt2 = pt1 pt3 = pt1 print (id(pt1), id(pt2), id(pt3)); # ,menampilkan id objek del pt1 del pt2 del pt3

Output dari kode di atas adalah seperti berikut:

140154852984592 140154852984592 140154852984592
Point dihancurkan

Pewarisan (Inheritansi) Kelas

Kita bisa menurunkan karakteristik sebuah kelas ke kelas baru, dibandingkan dengan membuat kelas baru dari awal. Turunannya disebut kelas anak (child class) dan yang mewariskannya disebut kelas induk (parent class).

Kelas anak mewarisi atribut dari kelas induk, dan kita bisa menggunakan atribut tersebut seolah atribut itu didefinisikan juga di dalam kelas anak. Kelas anak juga bisa menimpa (override) data dan metode dari induknya dengan data dan metodenya sendiri.

Satu kelas anak bisa mewarisi karakteristik dari satu atau beberapa kelas induk.

Sintaks

Pewarisan memiliki sintaks sebagai berikut:

class SubClassName (ParentClass1[, ParentClass2, ...]):
    """docstring"""
    class_body

Contoh

class Induk: # mendefinisikan kelas Induk parent_attr = 100 def __init__(self): print ("Memanggil konstruktor induk") def parent_method(self): print ('Memanggil metode induk') def set_attr(self, attr): Induk.parent_attr = attr def get_attr(self): print ("Attribut induk :", Induk.parent_attr) class Anak(Induk): # mendefinisikan kelas Anak def __init__(self): print ("Memanggil konstruktor Anak") def child_method(self): print ('Memanggil metode Anak') c = Anak() # instansiasi kelas Anak c.child_method() # Anak memanggil metodenya c.parent_method() # memanggil metode Induk c.set_attr(200) # kembali memanggil metode Induk c.get_attr() # kembali memanggil metode Induk

Output dari kode di atas adalah seperti berikut:

Memanggil konstruktor Anak
Memanggil metode Anak
Memanggil metode induk
Attribut induk: 200

Dengan cara yang sama, kita bisa membuat mewariskan beberapa induk ke satu anak seperti berikut:

class A:      # mendefinisikan kelas A
.....

class B:      # mendefinisikan kelas B
.....

class C(A, B): # mendefinisikan turunan dari kelas A dan B
.....

Kita bisa menggunakan fungsi issubclass() atau isinstance() untuk memeriksa relasi antara dua kelas atau objek.

  • Fungsi issubclass(sub, sup) mengembalikan True jika sub merupakan anak dari sup
  • Fungsi isinstance(obj, Class) mengembalikan True jika obj adalah instance dari kelas Class atau subkelas dari Class.

Metode Overriding

Kita bisa mengabaikan fungsi dari kelas induk di dalam kelas anak. Alasan untuk melakukan overriding adalah karena kita memodifikasi atau mengubah metode yang sudah diturunkan dari kelas induk di dalam kelas anak. Perhatikan contoh berikut:

class Induk: def my_method(self): print("Memanggil metode induk") class Anak(Induk): def my_method(self): print("Memanggil metode anak") c = Anak() c.my_method()

Hasil keluaran dari kode di atas adalah:

Memanggil metode anak

Perhatikan pada contoh di atas bagaimana kita mengabaikan metode yang dari induk dan mendefinisikan sendiri metode dengan nama yang sama di kelas anak. Dan yang dijalankan adalah metode yang ada di kelas anak.


Overloading Metode

Tabel berikut menunjukkan beberapa fungsi umum yang sering di-override di dalam kelas:

No Metode, Deskripsi, dan Contoh
1 __init__(self[, args…])
Fungsi: Konstruktor (argumen bersifat opsional)
Contoh pemanggilan: obj = className(args)
2 __del__(self)
Fungsi: Destruktor, menghapus sebuah objek
Contoh pemanggilan: del obj
3 __repr__(self)
Fungsi: Representasi string yang bisa dievaluasi
Contoh pemanggilan: repr(obj)
4 __str__(self)
Fungsi: Representasi string yang bisa dicetak
Contoh pemanggilan: str(obj)
5 __cmp__(self, x)
Fungsi: Membandingkan objek
Contoh pemanggilan: cmp(obj, x)

Overloading Operator

Misalkan kita membuat sebuah kelas Vector untuk menunjukkan vektor dua dimensi. Apa yang terjadi bila kita menggunakan tanda + untuk menjumlahkan keduanya?

Kita bisa mendefinisikan metode __add__ dalam kelas kita untuk melakukan penjumlahan vektor dan kemudian operator + akan berfungsi sesuai kehendak kita. Perhatikan contoh berikut:

class Vector: def __init__(self, a, b): self.a = a self.b = b def __str__(self): return 'Vector (%d, %d)' % (self.a, self.b) def __add__(self, other): return Vector(self.a + other.a, self.b + other.b) v1 = Vector(5, 10) v2 = Vector(4, -2) print(v1 + v2)

Saat program di atas dieksekusi, hasilnya akan muncul seperti berikut:

Vector(9, 8)

Menyembunyikan Data (Data Hiding)

Sebuah atribut objek bisa dibuat terlihat ataupun tersembunyi dari luar kelas. Caranya di Python adalah dengan memberi nama atribut dengan di awali tanda underscore dua kali. Dengan begitu, atribut tersebut tidak akan dapat tampak dari luar kelas.


Contoh

class Counter:
    __secret_count = 0
    
    def count(self):
        self.__secret_count += 1
        print(self.__secret_count)

counter = Counter()
counter.count()
counter.count()
print(counter.__secret_count)

Bila kode di atas dijalankan maka keluarannya akan menampilkan hasil seperti berikut:

1
2
Traceback(most recent call last):
File "test.py", line 12, in <module>
Attribut Error: Counter instance has no attribute '__secret_count'

Python melindungi attribut tersebut dengan mengubah namanya. Kita bisa mengakses atribut seperti itu dengan format object._className__attrName seperti berikut:

print(counter._Counter__secret_count)

Output dari program di atas adalah seperti berikut:

1
2
3
Bagikan:

Tinggalkan Balasan