# Bab 7. OBJECT ORIENTED PROGRAMMING** **OBJEKTIF:** 1. Mahasiswa Mampu Memahami Prosedural dan *Object Oriented Programming*. 2. Mahasiswa Mampu Memahami *Class* pada Python. 3. Mahasiswa Mampu Memahami *Inheritance* pada Pyhton. 4. Mahasiswa Mampu Memahami *Polymorphism* pada Python --- **7.1 PROSEDURAL DAN OBJECT ORIENTED PROGRAMMING** ​ Terdapat dua Metode pemrogramana yang digunakan saat ini yaitu: 1. Prosedural: Memecah program menjadi prosedur-prosedur (fungsi-fungsi) 2. *Object oriented*: Memecah program menjadi *object*-*object* Pada prosedural *programming* data dan fungsi terpisah. Sedangkan pada *object oriented programming* data dan fungsi adalah satu kesatuan. Ilustrasi pengolahan data pada prosedural *programming* dan OOP: <img src="C:\Users\Asus\AppData\Roaming\Typora\typora-user-images\image-20210728152522047.png" alt="image-20210728152522047" style="zoom:47%;" /> Pada prosedural *programming* kita membuat program dengan pendekatan *top down* yaitu kita merancang terlebih dahulu logika utama (fungsi main) dari program lalu memecah program menjadi fungsi-fungsi. Sedangkan pada OOP, kita membuat program dengan pendekatan *bottom up* yaitu kita merancang program dengan membuat *object*-*object* dasar terlebih dahulu dan mengembangkan *object*-*object* tersebut lalu mengintegrasikan *object*-*object* dalam fungsi main. Memecah program menjadi fungsi-fungsi yang kita lakukan pada topik-topik sebelumnya adalah prosedural *programming*. Python selain mendukung prosedural *programming* juga mendukung *object oriented programming*. Pada bagian ini kita akan membahas *object oriented programming* **7.2 CLASS** ​ *Object* adalah entitas program yang terdiri dari data dan fungsi. Data yang berada di dalam *object* disebut sebagai *attribute*. Fungsi yang dilakukan oleh *object* disebut sebagai *method*. Sebelum sebuah *object* dapat dibuat, kita harus mendesain *object* tersebut dengan mendefinisikan *class*. Kita dapat membayangkan *class* sebagai “cetakan” yang digunakan untuk mencetak *object*-*object*. <img src="C:\Users\Asus\AppData\Roaming\Typora\typora-user-images\image-20210728153528610.png" alt="image-20210728153528610" style="zoom:67%;" /> *Syntax* umum penulisan definisi *class*: <img src="C:\Users\Asus\AppData\Roaming\Typora\typora-user-images\image-20210729165619403.png" alt="image-20210729165619403" style="zoom:63%;" /> Dalam *body class* kita menuliskan: 1. *method* `__ init__` (dua *underscore* sebelum dan setelah kata `init`) untuk mendefinisikan *attribute*-*attribute* apa saja yang terdapat dalam *class* dan untuk menginisialisasi nilai-nilai *attribute* saat instansiasi 2. *method*-*method* lainnya Contoh definisi *class*: <img src="C:\Users\Asus\AppData\Roaming\Typora\typora-user-images\image-20210729171421271.png" alt="image-20210729171421271" style="zoom:63%;" /> **7.2.1 METHOD __ init__** ​ *Method* `__init__` adalah *method* khusus yang digunakan untuk menginisialisasi (memberikan nilai awal) ke *attribute*-*attribute* dari *object*. *Method* `__init__` dipanggil otomatis ketika kita membuat *object* (menginstansiasi) dari *class*. Untuk membuat *object* (menginstansiasi) dari *class* kita memanggil nama *class* dan memberikan nilai argumen ke parameter-parameter dari *method* `__init__` <img src="C:\Users\Asus\AppData\Roaming\Typora\typora-user-images\image-20210729172201240.png" alt="image-20210729172201240" style="zoom:64%;" /> **7.2.2 MENGINSTANSIASI CLASS** ​ Kita dapat menginstansiasi lebih dari satu *object* dari suatu *class*. ```python heli = Dog('terrier', 'coklat') bleki = Dog('bulldog', 'hitam') snowy = Dog('terrier', 'putih') ``` Setiap *object* akan mempunyai nilai-nilai *attribute* masing-masing. <img src="C:\Users\Asus\AppData\Roaming\Typora\typora-user-images\image-20210729172520383.png" alt="image-20210729172520383" style="zoom:64%;" /> ​ Misalkan, kita membuat sebuah program yang mensimulasikan pelemparan koin. Dalam program ini, kita mensimulasikan pelemparan koin berulang kali dan setiap lemparan program menentukan sisi koin (“*Heads*” atau “*Tails*”) yang menghadap atas ketika jatuh. Untuk merepresentasikan koin, kita membuat sebuah *class* dengan nama *Coin*. <img src="C:\Users\Asus\AppData\Roaming\Typora\typora-user-images\image-20210729172733771.png" alt="image-20210729172733771" style="zoom:50%;" /> contoh program: ```python import random # class Coin mensimulasikan sebuah coin # yang dapat dilempar class Coin: # Method __init__ menginisialisasi # attribute data sisiatas dengan 'Heads'. def __init__(self): self.sisiatas = 'Heads' # Method lempar menggenerasi sebuah angka random # di antara 0 s.d 1. Jika angka = 0, maka sisiatas # ditetapkan sebagai 'Heads' # Jika = 1, maka sisiatas ditetapkan sebagai 'Tails' def lempar(self): if random.randint(0, 1) == 0: self.sisiatas = 'Heads' else: self.sisiatas = 'Tails' # Method get_sideup mengembalikan nilai # yang direferensikan oleh sisiatas def get_sisiatas(self): return self.sisiatas # Fungsi main def main(): # Buat object Coin my_coin = Coin() # Tampilkan sisi coin yang menghadap atas print('Sisi koin yang menghadap atas:', my_coin.get_sisiatas()) # Lempar koin print('Saya melempar koin...') my_coin.lempar() # Tampilkan sisi dari koin yang menghadap atas print('Sisi koin yang menghadap atas:', my_coin.get_sisiatas()) # Panggil fungsi main main() ``` *Output*: Sisi koin yang menghadap atas: Heads Saya melempar koin... Sisi koin yang menghadap atas: Tails ```python import random # class Coin mensimulasikan sebuah coin # yang dapat dilempar class Coin: # Method __init__ menginisialisasi # attribute data sisiatas dengan 'Heads'. def __init__(self): self.sisiatas = 'Heads' # Method lempar menggenerasi sebuah angka random # di antara 0 s.d 1. Jika angka = 0, maka sisiatas # ditetapkan sebagai 'Heads' # Jika = 1, maka sisiatas ditetapkan sebagai 'Tails' def lempar(self): if random.randint(0, 1) == 0: self.sisiatas = 'Heads' else: self.sisiatas = 'Tails' # Method get_sideup mengembalikan nilai # yang direferensikan oleh sisiatas def get_sisiatas(self): return self.sisiatas ``` Catatan: *Class Coin* mempunyai: 1. Satu *Attribute*: sisiatas 2. Tiga *Method*: `__ init__` , lempar , get_sisiatas ![image-20210729174122891](C:\Users\Asus\AppData\Roaming\Typora\typora-user-images\image-20210729174122891.png) Fungsi `main` yang menggunakan *object Coin*: ![image-20210729174329024](C:\Users\Asus\AppData\Roaming\Typora\typora-user-images\image-20210729174329024.png) Program berikut mendemonstrasikan pembuatan lebih dari satu *object Coin*: ```python # coin_multiple_instance.py # Mendemokan tiga object coin import random # class Coin mensimulasikan sebuah coin # yang dapat dilempar class Coin: # Method __init__ menginisialisasi # attribute data sisiatas dengan 'Heads'. def __init__(self): self.__sisiatas = 'Heads' # Method lempar menggenerasi sebuah angka random # di antara 0 s.d 1. Jika angka = 0, maka sisiatas # ditetapkan sebagai 'Heads' # Jika = 1, maka sisiatas ditetapkan sebagai 'Tails' def lempar(self): if random.randint(0, 1) == 0: self.__sisiatas = 'Heads' else: self.__sisiatas = 'Tails' # Method get_sisiatas mengembalikan nilai # yang direferensikan oleh sisiatas def get_sisiatas(self): return self.__sisiatas # Fungsi main def main(): # Buat tiga object (instance) dari class Coin coin1 = Coin() # Instansiasi Coin dan namakan dengan coin1 coin2 = Coin() # Instansiasi Coin dan namakan dengan coin2 coin3 = Coin() # Instansiasi Coin dan namakan dengan coin3 # Tampilkan sisi atas dari setiap koin print('Saya mempunyai tiga koin dengan sisi menghadap atas:') print(coin1.get_sisiatas()) print(coin2.get_sisiatas()) print(coin3.get_sisiatas()) print() # Lempar koin print('Saya melempar tiga koin...') print() coin1.lempar() coin2.lempar() coin3.lempar() # Tampilkan sisi atas dari setiap koin print('Sekarang sisi-sisi berikut yang menghadap atas:') print(coin1.get_sisiatas()) print(coin2.get_sisiatas()) print(coin3.get_sisiatas()) print() # Panggil fungsi main main() ``` *Output*: Saya mempunyai tiga koin dengan sisi menghadap atas: Heads Heads Heads Saya melempar tiga koin... Sekarang sisi-sisi berikut yang menghadap atas: Heads Heads Tails **7.2.3 ENCAPSULATION** ​ Prinsip utama OOP adalah *encapsulation* (pengkapsulan) yang berarti *attribute* dan *method* merupakan satu kesatuan dan *attribute* haruslah *private* . *Attribute* haruslah *private* berarti *attribute*-*attribute* *object* tersembunyi dari kode di luar *object* dan hanya *method* dalam *object* tersebut yang dapat mengakses dan membuat perubahan ke data *attribute*. Dengan menyembunyikan *attribute* dari kode di luar *object*, kita memproteksi *attribute*-*attribute* dari perubahan yang membuat *object* kita tidak konsisten dengan desain *class* kita. <img src="C:\Users\Asus\AppData\Roaming\Typora\typora-user-images\image-20210729175417627.png" alt="image-20210729175417627" style="zoom:47%;" /> ​ Pada contoh *class Coin* sebelumnya, *attribute* sisiatas belum tersembunyi. Karena belum tersembunyi, kita bisa mengubah *attribute* sisiatas tanpa melalui *method*. ```python my_coin = Coin() my_coin.sisiatas = 'Head' ``` Pada contoh di atas kita mengubah sisiatas menjadi nilai '*Head*' dan ini tidak sesuai dengan desain *class* kita, karena kita mendesain *attribute* sisiatas hanya dapat bernilai '*Heads*' atau '*Tails*'. Untuk membuat *attribute* menjadi *private* kita menambahkan dua karakter *underscore* sebelum nama *attribute*: ```python self.__sisiatas = 'Heads' ``` Contoh program *class Coin* yang menyembunyikan *attribute*-nya: ```python import random # class Coin mensimulasikan sebuah coin yang dapat dilempar class Coin: # Method __init__ menginisialisasi attribute data sisiatas dengan 'Heads'. def __init__(self): self.__sisiatas = 'Heads' # Method lempar menggenerasi sebuah angka random # di antara 0 s.d 1. Jika angka = 0, maka sisiatas ditetapkan sebagai 'Heads' # Jika = 1, maka sisiatas ditetapkan sebagai 'Tails' def lempar(self): if random.randint(0, 1) == 0: self.__sisiatas = 'Heads' else: self.__sisiatas = 'Tails' # Method get_sisiatas mengembalikan nilai yang direferensikan oleh sisiatas def get_sisiatas(self): return self.__sisiatas ``` Kita menyembunyikan attribute dengan menambahkan dua *underscore* sebelum nama *attribute*. <img src="C:\Users\Asus\AppData\Roaming\Typora\typora-user-images\image-20210730075021170.png" alt="image-20210730075021170" style="zoom:60%;" /> Ketika kita mencoba mengakses *attribute* secara langsung atau mencoba mengubah nilainya tanpa melalui *method* maka interpreter akan memberikan *error* ```python my_coin = Coin() print(my_coin.__sisiatas) ``` <img src="C:\Users\Asus\AppData\Roaming\Typora\typora-user-images\image-20210730075206456.png" alt="image-20210730075206456" /> ​ Pada contoh program yang mensimulasikan lemparan koin, kita menuliskan definisi *class Coin* dan fungsi `main` yang menggunakan *class Coin* dalam satu *file*. Ini tidak masalah jika kita menuliskan program kecil yang hanya menggunakan satu atau dua *class*, namun ketika kita menuliskan program dengan banyak *class* kita perlu mengorganisasi *class*-*class* tersebut. Programmer umumnya mengorganisasi *class* dalam sebuah *module*. Contoh *class Coin* pada *module*: File: coin.py ```python import random # class Coin mensimulasikan sebuah coin # yang dapat dilempar class Coin: # Method __init__ menginisialisasi # attribute data sisiatas dengan 'Heads'. def __init__(self): self.__sisiatas = 'Heads' # Method lempar menggenerasi sebuah angka random # di antara 0 s.d 1. Jika angka = 0, maka sisiatas # ditetapkan sebagai 'Heads' # Jika = 1, maka sisiatas ditetapkan sebagai 'Tails' def lempar(self): if random.randint(0, 1) == 0: self.__sisiatas = 'Heads' else: self.__sisiatas = 'Tails' # Method get_sisiatas mengembalikan nilai yang # direferensikan oleh sisiatas def get_sisiatas(self): return self.__sisiatas ``` File: test_coin.py ```python import coin # Fungsi main def main(): # Buat sebuah object dari class Coin my_coin = coin.Coin() # Tmapilkan sisi coin yang menghadap atas print('Sisi koin yang menghadap atas:', my_coin.get_sisiatas()) # Lempar koin print('Saya melempar koin...') my_coin.lempar() # Tampilkan sisi dari koin yang menghadap atas print('Sisi koin yang menghadap atas: ', my_coin.get_sisiatas()) # Panggil fungsi main main() ``` <img src="C:\Users\Asus\AppData\Roaming\Typora\typora-user-images\image-20210730112334483.png" alt="image-20210730112334483" style="zoom:60%;" /> **7.2.4 UNIFIED MODELING LANGUANGE** ​ Ketika mendesain *class*, programmer umumnya menggunakan *diagram Unified Modeling Languange* (atau disingkat dengan UML) untuk merepresentasikan desain dari *class*. *Diagram* UML adalah sebuah kotak yang dibagi menjadi tiga bagian: 1. Bagian atas: nama *class* 2. Bagian tengah: *attribute*-*attribute* dari *class* 3. Bagian bawah: *method*-*method* dari *class* <img src="C:\Users\Asus\AppData\Roaming\Typora\typora-user-images\image-20210730112852973.png" alt="image-20210730112852973" style="zoom:67%;" /> Misalkan kita membuat sebuah *class BankAccount* yang mensimulasikan sebuah rekening tabungan bank: <img src="C:\Users\Asus\AppData\Roaming\Typora\typora-user-images\image-20210730113138869.png" alt="image-20210730113138869" style="zoom:57%;" /> *Class BankAccount* merepresentasikan rekening tabungan bank: ```python # bankaccount.py # class BankAccount mensimulasikan sebuah rekening bank class BankAccount: # Method __init__ menginisilasiasi attribute __saldo def __init__(self, saldo): self.__saldo = saldo # Method deposit (menabung) melakukan setoran # sejumlah uang ke rekening sehingga saldo bertambah def deposit(self, jumlah): self.__saldo += jumlah # Method withdraw (menarik) melakukan penarikan # sejumlah uang dari rekening bank def withdraw(self, jumlah): if self.__saldo >= jumlah: self.__saldo -= jumlah else: print('Gagal: Dana tidak mencukupi') # Method get_saldo mengembalikan saldo def get_saldo(self): return self.__saldo ``` Program berikut mendemonstrasikan *class BankAccount*: ```python # test_bankaccount.py # Program ini mendemonstrasikan object dari class BankAccount import bankaccount def main(): # Buat saldo awal saldo_awal = float(input('Masukkan saldo awal: ')) # Buat object BankAccount tabungan = bankaccount.BankAccount(saldo_awal) # Tabung gaji pengguna gaji = float(input('Masukkan gaji Anda minggu ini: ')) print('Saya akan depositokan gaji Anda ke rekening Anda.') tabungan.deposit(gaji) # Tampilkan saldo print(f'Saldo Anda adalah Rp.{tabungan.get_saldo():,.2f}’) # Mengambil sejumlah uang cash = float(input( 'Berapa banyak uang yang ingin Anda ambil? ')) print('Saya akan ambil uang tersebut dari rekening Anda.') tabungan.withdraw(cash) # Tampilkan saldo print(f'Saldo Anda adalah Rp.{tabungan.get_saldo():,.2f}') # Panggil fungsi main main() ``` *Output*: Masukkan saldo awal: 1000000 Masukkan gaji Anda minggu ini: 250000 Saya akan depositokan gaji Anda ke rekening Anda. Saldo Anda adalah Rp.1,250,000.00 Berapa banyak uang yang ingin Anda ambil? 100000 Saya akan ambil sebanyak uang tersebut dari rekening Anda. Saldo Anda adalah Rp.1,150,000.00 **7.2.5 METHOD __ str__ ** ​ Seringkali kita perlu menampilkan sebuah pesan yang mengindikasikan *state* dari *object*. *State* dari *object* adalah nilai-nilai *attribute* dalam satu waktu. Menampilkan *state* adalah hal yang umum dilakukan, sehingga programmer biasanya mempunyai sebuah *method* mengembalikan sebuah `string` yang menampilkan *state* dari *object*. Dalam python, kita memberikan nama *method* yang mengembalikan *state* dari *object* dengan nama spesial: `__str__` Menambahkan *method* `__ str__`` pada *class BankAccount*: ```python def __str__(self): return f'Saldo Anda adalah Rp.{self.__saldo:,.2f}' ``` Kita tidak memanggil langsung *method* `__str__`, *method* ini dipanggil otomatis ketika kita memberikan argument nama *object* ke fungsi `print`: ```python tabungan = BankAccount(100000) print(tabungan) ``` Catatan: Ketika kita memberikan nama *object* sebagai argument ke fungsi `print`, interpreter otomatis memanggil *method* `__str__`. *Class BankAccount* dengan *method* `__str__`: ```python # bankaccount2.py # class BankAccount mensimulasikan sebuah rekening bank class BankAccount: # Method __init__ menginisilasiasi attribute __saldo def __init__(self, saldo): self.__saldo = saldo # Method deposit (menabung) melakukan setoran # sejumlah uang ke rekening sehingga saldo bertambah def deposit(self, jumlah): self.__saldo += jumlah # Method withdraw (menarik) melakukan penarikan # sejumlah uang dari rekening bank def withdraw(self, jumlah): if self.__saldo >= jumlah: self.__saldo -= jumlah else: print('Gagal: Dana tidak mencukupi') # Method get_saldo mengembalikan saldo def get_saldo(self): return self.__saldo # Method __str__ mengembalikan sebuah string yang menunjukkan state dari object def __str__(self): return f'Saldo Anda adalah Rp.{self.__saldo:,.2f}' ``` Program yang mendemonstrasikan *BankAccount* dengan *method* `__str__`: ```python # test_bankaccount2.py # Program ini mendemonstrasikan object dari class BankAccount import bankaccount2 def main(): # Buat saldo awal saldo_awal = float(input('Masukkan saldo awal: ')) # Buat object BankAccount tabungan = bankaccount2.BankAccount(saldo_awal) # Tabung gaji pengguna gaji = float(input('Masukkan gaji Anda minggu ini: ')) print('Saya akan depositokan gaji Anda ke rekening Anda.') tabungan.deposit(gaji) # Tampilkan saldo print(tabungan) # Mengambil sejumlah uang cash = float(input('Berapa banyak uang yang ingin Anda ambil? ')) print('Saya akan ambil uang tersebut dari rekening Anda.') tabungan.withdraw(cash) # Tampilkan saldo print(tabungan) # Panggil fungsi main main() ``` *Output*: Masukkan saldo awal: 1000000 Masukkan gaji Anda minggu ini: 250000 Saya akan depositokan gaji Anda ke rekening Anda. Saldo Anda adalah Rp.1,250,000.00 Berapa banyak uang yang ingin Anda ambil? 100000 Saya akan ambil sebanyak uang tersebut dari rekening Anda. Saldo Anda adalah Rp.1,150,000.00 **7.2.6 METHOD ACCESSOR DAN MUTATOR** ​ *Encapsulation* pada OOP berarti kita harus mendesain *class* kita dengan menyembunyikan *attribute*. Ini juga berarti kita harus menyediakan *method*-*method* yang dapat digunakan untuk mengubah nilai *attribute* dan yang dapat digunakan untuk mengakses nilai *attribute*. *Method*-*method* untuk mengakses nilai *attribute* tanpa mengubah nilainya disebut sebagai *method accessor* dan *method*-*method* untuk mengubah nilai *attribute* disebut sebagai *method mutator*. Pada contoh *class BankAccount* kita mempunyai *method accessor* yang kita gunakan untuk mengakses nilai *attribute* saldo: *method* get_saldo. Namun pada *class BankAccount* kita tidak mempunyai *method mutator* karena kita mendesain *class* kita dengan tidak memperbolehkan *attribute* saldo diubah langsung namun melalui *method*-*method* tidak langsung: *method* deposit dan *method* withdraw. Misalkan kita menambahkan sebuah *attribute* nomor_rekening pada *class BankAccount* dan kita membolehkan *attribute* ini ditetapkan dan diakses oleh kode di luar *object* melalui sebuah *method mutator* dan sebuah *method accessor*. <img src="C:\Users\Asus\AppData\Roaming\Typora\typora-user-images\image-20210730115926234.png" alt="image-20210730115926234" style="zoom:67%;" /> *Method*-*method accessor* umumnya dinamakan dengan diawali kata *get* yang diikuti dengan nama *attribute*, sehingga *method accessor* seringkali disebut juga sebagai *getters*. Sedangkan *method*-*method* *mutator* umumnya dinamakan dengan diawali kata *set* yang diikuti dengan nama *attribute*, sehingga *method mutator* seringkali disebut juga sebagai *setters*. *Class BankAccount* dengan *attribute* nomor_rekening dan *method accessor* dan *mutatornya*: ```python # bankaccount3.py # class BankAccount mensimulasikan sebuah rekening bank class BankAccount: # Method __init__ menginisilasiasi attribute __saldo def __init__(self, saldo, nomor_rekening): self.__saldo = saldo self.__nomor_rekening = nomor_rekening # Method deposit (menabung) melakukan setoran # sejumlah uang ke rekening sehingga saldo bertambah def deposit(self, jumlah): self.__saldo += jumlah # Method withdraw (menarik) melakukan penarikan # sejumlah uang dari rekening bank def withdraw(self, jumlah): if self.__saldo >= jumlah: self.__saldo -= jumlah else: print('Gagal: Dana tidak mencukupi') # Method get_saldo mengembalikan saldo def get_saldo(self): return self.__saldo # Method accessor untuk nomor_rekening def get_nomor_rekening(self): return self.__nomor_rekening # Method mutator untuk nomor_rekening def set_nomor_rekening(self, nomor_rekening): self.__nomor_rekening = nomor_rekening # Method __str__ mengembalikan sebuah string # yang menunjukkan state dari object def __str__(self): return f'Nomor rekening: {self.__nomor_rekening}' + \ f'\nSaldo: Rp.{self.__saldo:,.2f}' ``` Program yang mendemonstrasikan *class BankAccount* dengan *attribute* nomor_rekening beserta *accessor* dan *mutator*nya: ```python # test_bankaccount3.py # Program ini mendemonstrasikan object dari class BankAccou nt import bankaccount3 def main(): # Buat saldo awal saldo_awal = float(input('Masukkan saldo awal: ')) # Buat object BankAccount tabungan = bankaccount3.BankAccount(saldo_awal, '123456789') # Tabung gaji pengguna gaji = float(input('Masukkan gaji Anda minggu ini: ')) print('Saya akan depositokan gaji Anda ke rekening Anda.') tabungan.deposit(gaji) # Tampilkan state print(tabungan) # Mengambil sejumlah uang cash = float(input('Berapa banyak uang yang ingin Anda ambil? ')) print('Saya akan ambil uang tersebut dari rekening Anda.') tabungan.withdraw(cash) # Tampilkan state print(tabungan) # Ubah nomor rekening nomor_rekening = input('Masukkan nomor rekening baru: ') tabungan.set_nomor_rekening(nomor_rekening) # Tampilkan nomor rekening print(f'Nomor rekening baru {tabungan.get_nomor_rekening()}') # Panggil fungsi main main() ``` *Output* program test_bankaccount3.py: Masukkan saldo awal: 1000000 Masukkan gaji Anda minggu ini: 250000 Saya akan depositokan gaji Anda ke rekening Anda. Nomor rekening: 123456789 Saldo: Rp.1,250,000.00 Berapa banyak uang yang ingin Anda ambil? 100000 Saya akan ambil uang tersebut dari rekening Anda. Nomor rekening: 123456789 Saldo: Rp.1,150,000.00 Masukkan nomor rekening baru: 234567890 Nomor rekening baru 234567890 **7.2.7 OBJEK SEBAGAI ARGUMEN FUNGSI** ​ Ketika kita membuat program yang berkerja dengan *object*, seringkali kita perlu membuat sebuah fungsi yang menerima *object* sebagai argument. Sebagai contoh, fungsi berikut menerima *object Coin* sebagai argument: ```python def status_koin(obj_coin): print('Sisi koin yang menghadap atas:', obj_coin.get_sisiatas()) ``` Kode berikut menunjukkan bagaimana kita membuat *object Coin* lalu memberikannya sebagai argument ke fungsi status_koin: ```python my_coin = coin.Coin() status_koin(my_coin) ``` Ketika kita memberikan argument berupa *object* ke suatu fungsi, variabel parameter dari fungsi tersebut akan menerima referensi ke *object* tersebut, sehingga kita dapat memanggil *method*-*method* dari *object* tersebut. Program yang mendemonstrasikan pemberian *object* ke fungsi: ```python # Program ini mendemonstrasikan pemberian argumen # berupa object ke fungsi import coin # Fungsi lempar_koin melempar koin def lempar_koin(obj_coin): obj_coin.lempar() # Fungsi main def main(): # Buat object Coin my_coin = coin.Coin() # Ini akan menampilkan 'Heads' print(my_coin.get_sisiatas()) # Berikan object my_coin ke fungsi lempar_koin lempar_koin(my_coin) # Ini akan menampilkan 'Heads' atau 'Tails' print(my_coin.get_sisiatas()) # Panggil fungsi main main() ``` *Output*: Heads Tails *Output*: Heads Heads **7.3 INHERITANCE** ​ Konsep penting OOP setelah *encapsulation* adalah *inheritance* (pewarisan). Konsep *inheritance* didasarkan pada pengamatan objek-objek di dunia nyata. Banyak objek merupakan versi spesialisasi dari object lainnya yang lebih generik. Misalkan, serangga merupakan jenis hewan dengan karakteristik-karakteristik tertentu sedangkan lebah dan belalang adalah versi spesialisasi dari serangga yang mempunyai (mewarisi) karakteristik-karakteristik dari serangga namun masing-masing juga mempunyai karakteristik-karakteristik khusus tertentu. <img src="C:\Users\Asus\AppData\Roaming\Typora\typora-user-images\image-20210730122121353.png" alt="image-20210730122121353" style="zoom:57%;" /> **7.3.1 SUPERCLASS DAN SUBCLASS** ​ *Class* yang merupakan versi spesialisasi dari suatu *class* disebut dengan *subclass* (atau *class* turunan). Sedangkan *class* yang merupakan versi generik dari suatu *class* disebut dengan *superclass* (atau *class* dasar). *Syntax* umum penulisan *subclass*: <img src="C:\Users\Asus\AppData\Roaming\Typora\typora-user-images\image-20210730122408778.png" alt="image-20210730122408778" style="zoom:57%;" /> *Subclass* akan mewarisi semua *attribute* dan *method* dari *superclass*. Pada *subclass* juga dapat ditambahkan *attribute*-*attribute* dan *method*-*method* baru yang membuatnya versi spesialisasi dari *superclass*. ![image-20210730122844562](C:\Users\Asus\AppData\Roaming\Typora\typora-user-images\image-20210730122844562.png) <img src="C:\Users\Asus\AppData\Roaming\Typora\typora-user-images\image-20210730144642514.png" alt="image-20210730144642514" style="zoom:65%;" /> <img src="C:\Users\Asus\AppData\Roaming\Typora\typora-user-images\image-20210730144751703.png" alt="image-20210730144751703" style="zoom:67%;" /> *Output*: Nama saya adalah Budi Susilo Umur saya adalah 17 Saya tingkat 12 **7.3.2 CONTOH PENERAPAN INHERITANCE** ​ Misalkan kita membuat sebuah program manajemen inventaris untuk suatu diler mobil: 1. Diler mobil menjual tiga jenis mobil: sedan, pickup, SUV 2. Kita mendesain program untuk menyimpan *attribute-attribute* data dari inventaris mobil berikut: merek, model, dan harga Selain tiga data yang sama untuk ketiga jenis mobil, setiap jenis mobil mempunyai data *attribute* tambahan sebagai berikut: 1. Sedan mempunyai *attribute* tambahan: banyak pintu (2 pintu atau 4 pintu) 2. Pickup mempunyai *attribute* tambahan: tipe penggerak (penggerak dua-roda atau penggerak empat-roda) 3. SUV mempunyai attribute tambahan: kapasitas penumpang (5 penumpang atau 7 penumpang) Jika kita membuat sebuah *class* untuk masing-masing jenis mobil, program yang akan kita tulis tidaklah efisien karena ketiga jenis mobil mempunyai banyak *attribute-attribute* yang sama. Daripada membuat tiga *class* berbeda, kita dapat membuat sebuah *class* generik (*superclass*) dengan *attribute-attribute* yang sama dari ketiga jenis mobil dan membuat tiga *class spesialisasi* (*subclass*) dengan *attribute* khusus dari ketiga jenis mobil. <img src="C:\Users\Asus\AppData\Roaming\Typora\typora-user-images\image-20210730145515990.png" alt="image-20210730145515990" style="zoom:67%;" /> *Superclass* Mobil: <img src="C:\Users\Asus\AppData\Roaming\Typora\typora-user-images\image-20210730150128094.png" alt="image-20210730150128094" style="zoom:57%;" /> *Subclass* Sedan: <img src="C:\Users\Asus\AppData\Roaming\Typora\typora-user-images\image-20210730150306735.png" alt="image-20210730150306735" style="zoom:57%;" /> *Subclass* Pickup: <img src="C:\Users\Asus\AppData\Roaming\Typora\typora-user-images\image-20210730150651077.png" alt="image-20210730150651077" style="zoom:57%;" /> *Subclass* SUV: <img src="C:\Users\Asus\AppData\Roaming\Typora\typora-user-images\image-20210730150538775.png" alt="image-20210730150538775" style="zoom:57%;" /> Simpan definisi *superclass* Mobil dan *subclass* Sedan, Pickup, SUV dalam *module* kendaraan lalu uji dengan program berikut: ```python # Program ini mendemonstrasikan class Sedan, Pickup, dan SUV import kendaraan def main(): # Buat object Sedan sedan = kendaraan.Sedan('BMW', '323', 500000000, 4) # Buat object Pickup pickup = kendaraan.Pickup('Toyota', 'Hilux', 350000000, '4WD') # Buat object SUV suv = kendaraan.SUV('Hyundai', 'Santa Fe', 550000000, 6) print('Data Kendaraan') print('=================') # Tampilkan data Sedan print('Merek:', sedan.get_merek()) print('Model:', sedan.get_model()) print('Jumlah Pintu:', sedan.get_pintu()) print() # Tampilkan data Pickup print('Merek:', pickup.get_merek()) print('Model:', pickup.get_model()) print(f'Harga: Rp.{pickup.get_harga(): ,.2f}') print('Tipe Penggerak:', pickup.get_tipe_penggerak()) print() # Tampilkan data SUV print('Merek:', suv.get_merek()) print('Model:', suv.get_model()) print(f'Harga: Rp.{suv.get_harga(): ,.2f}') print('Kapasitas Penumpang:', suv.get_kap_penumpang()) print() # Panggil fungsi main main() ``` *Output*: Data Kendaraan ================= Merek: BMW Model: 323 Harga: Rp. 500,000,000.00 Jumlah Pintu: 4 Merek: Toyota Model: Hilux Harga: Rp. 350,000,000.00 Tipe Penggerak: 4WD Merek: Hyundai Model: Santa Fe Harga: Rp. 550,000,000.00 Kapasitas Penumpang: 6 <img src="C:\Users\Asus\AppData\Roaming\Typora\typora-user-images\image-20210730153015066.png" alt="image-20210730153015066" style="zoom:67%;" /> **7.4 POLYMORPHISM** ​ Konsep penting OOP setelah *encapsulation* dan *inheritance* adalah *polymorphism*. “*Poly*” berarti banyak dan “*Morphism*” berarti bentuk. *Polymorphism* diartikan sebagai kemampuan objek untuk mempunyai bentuk yang berbeda-beda. *Polymorphism* memungkinkan *method* dalam *subclass* memiliki nama yang sama seperti *method* pada *superclass* namun mempunyai implementasi berbeda. Proses untuk mendefinisikan *method* dengan nama sama namun dengan implementasi berbeda ini disebut dengan *method overriding*. Contoh Polymorphism: <img src="D:\ilab wfh\KOMP-00-023\revisi wfh\bab 7\gambar 7\28.jpg" alt="28" style="zoom:57%;" /> Contoh program: ```python # hewan.py # Class mamalia merepresentasikan mamalia generik class Mamalia: # Method __init__ menerima sebuah argumen untuk # spesies mamalia def __init__(self, spesies): self.__spesies = spesies # Method tampilkan_spesies menampilkan sebuah pesan # yang menunjukkan spesies dari mamalia. def tampilkan_spesies(self): print('Saya adalah seekor', self.__spesies) # Method buat_suara menampilkan suara generik dari mamalia def buat_suara(self): print('Grrrr') ``` Catatan: Class Mamalia mempunyai tiga method: `__init__()`, tampilkan_spesies(), buat_suara() Contoh kode yang membuat *instance* dari *class* Mamalia dan memanggil *method-method* dalam *class* tersebut: ```python import hewan mamalia = hewan.Mamalia('Mamalia Generik') mamalia.tampilkan_spesies() mamalia.buat_suara() ``` *Output*: Saya adalah seekor Mamalia Generik Grrrrr ```python # Class Anjing adalah subclass dari Mamalia class Anjing(Mamalia): # Method __init__ memanggil method __init__ # dari superclass dan memberikan argumen spesies 'Anjing' def __init__(self): Mamalia.__init__(self, 'Anjing') # Method buat_suara meng-override method buat_suara # dari superclass Mamalia def buat_suara(self): print('Guk! Guk!') ``` *Output*: Saya adalah seekor Anjing Guk! Guk! Catatan: 1. *Class* Anjing adalah *subclass* dari *class* Mamalia. 2. Method `__init__` yang kita definisikan pada *class* Anjing meng*override* *method* `__init__` yang diwariskan dari *superclass* Mamalia. 3. *Class* Mamalia yang merupakan *superclass* dari *class* Anjing mempunyai *method* buat_suara. Pada *subclass* Anjing kita meng-*override method* buat_suara dengan mendefiniskan *method* dengan nama yang sama namun dengan implementasi berbeda (disini kita menampilkan `string` 'Guk! Guk!' ke layar). Contoh kode yang membuat *instance* dari *class* Anjing dan memanggil *method*-*method*nya: ```python import hewan anjing = hewan.Anjing() anjing.tampilkan_spesies() anjing.buat_suara() ``` Catatan: 1. Karena di *subclass* Anjing tidak ada definisi *method* tampilkan_spesies maka *method* tampilkan_spesies dari *superclass* Mamalia yang dipanggil. 2. Pada *subclass* Anjing kita meng-*override* *method* buat_suara() sehingga *method* yang kita definisikan pada *subclass* Anjing yang digunakan ketika kita memanggil *method* buat_suara() pada *object* Anjing. ```python # Class Kucing adalah subclass dari class Mamalia class Kucing(Mamalia): # Method __init__ memanggil method __init__ # dari superclass dan memberikan argumen spesies 'Kucing' def __init__(self): Mamalia.__init__(self, 'Kucing') # Method buat_suara meng-override method buat_suara # dari superclass Mamalia def buat_suara(self): print('Meong!') ``` *Output*: Saya adalah seekor Kucing Meong! Contoh kode yang membuat *instance* dari *class* Kucing dan memanggil *method-methodnya*: ```python import hewan kucing = hewan.Kucing() kucing.tampilkan_spesies() kucing.buat_suara() ``` Catatan: 1. Karena di *subclass* Kucing tidak ada definisi *method* tampilkan_spesies maka *method* tampilkan_spesies dari *superclass* Mamalia yang dipanggil. 2. Pada *subclass* Kucing kita meng-*override* *method* buat_suara() sehingga *method* yang kita definisikan pada *subclass* Kucing yang digunakan ketika kita memanggil *method* buat_suara() pada *object* Kucing. **7.4.1 KEUNTUNGAN POLYMORPHISM** ​ *Polymorphism* memberikan fleksibilitas dalam mendesain program. Sebagai contoh, kita dapat membuat sebuah fungsi seperti berikut: ```python def tampilkan_info_mamalia(makhluk): makhluk.tampilkan_spesies() makhluk.buat_suara() ``` Kita bisa memanggil fungsi info_mamalia dengan argumen *object* apapun selama *object* tersebut memiliki *method* tampilkan_spesies dan buat_suara. Tanpa *polymorphism* kita harus membuat sebuah fungsi untuk setiap jenis *object*. ```python # demo_polymorphism_fungsi.py # Program ini mendemonstrasikan fungsi yang menerima object dengan polymorphism import hewan # Fungsi ini menerima object sebagai argumen # dan memanggil method tampilkan_spesies dan buat_suara def tampilkan_info_mamalia(makhluk): makhluk.tampilkan_spesies() makhluk.buat_suara() # Fungsi main def main(): # Buat object Mamalia, object Anjing, dan object Kucing mamalia = hewan.Mamalia('Mamalia Generik') anjing = hewan.Anjing() kucing = hewan.Kucing() # Tampilkan informasi spesies satu per satu print('Berikut ini beberapa hewan dan') print('suara yang mereka buat.') tampilkan_info_mamalia(mamalia) print() tampilkan_info_mamalia(anjing) print() tampilkan_info_mamalia(kucing) # Panggil fungsi main main() ``` *Output*: Berikut ini beberapa hewan dan suara yang mereka buat. Saya adalah seekor Mamalia Generik Grrrr Saya adalah seekor Anjing Guk! Guk! Saya adalah seekor Kucing Meong! **7.4.2 FUNGSI ISINSTANCE** ​ Ketika kita membuat fungsi yang menerima sebuah *object* sebagai argumen dan memanggil *method-methodnya* kita harus memastikan *object* tersebut memiliki *method-method* yang dipanggil. Misalkan: ```python # salah_tipe.py def tampilkan_info_mamalia(makhluk): makhluk.tampilkan_spesies() makhluk.buat_suara() def main(): # Berikan sebuah string ke tampilkan_info_mamalia tampilkan_info_mamalia('Saya adalah string') main() ``` *Output* dari program akan menghasilkan *error*, karena *object* yang diberikan ke fungsi tidak mempunyai *method-method* yang dipanggil dalam fungsi: <img src="C:\Users\Asus\AppData\Roaming\Typora\typora-user-images\image-20210730160315596.png" alt="image-20210730160315596" style="zoom:57%;" /> Kita bisa menggunakan fungsi `isinstance` untuk menentukan apakah suatu *object* adalah turunan dari *class* tertentu atau *subclass* dari suatu *class*. *Syntax* pemanggilan fungsi `isinstance`: ```python isintance(object, namaClass) ``` Jika *object* yang direferensikan dari *object* merupakan turunan dari nama *class* atau *subclass* dari nama *class f*ungsi mengembalikan nilai *True* dan mengembilkan nilai *False* jika bukan. Kita dapat menggunakan fungsi `isinstance` sebagai *exception handler*. ```python def tampilkan_info_mamalia(makhluk): if isinstance(makhluk, hewan.Mamalia): makhluk.tampilkan_spesies() makhluk.buat_suara() else: print('Ini bukan mamalia.') ``` Contoh program dari fungsi `isinstance` ```python # demo_polymorphism_fungsi2.py # Program ini mendemonstrasikan fungsi yang menerima object dengan polymorphism import hewan # Fungsi ini menerima object sebagai argument dan memanggil method tampilkan_spesies dan buat_suara def tampilkan_info_mamalia(makhluk): if isinstance(makhluk, hewan.Mamalia): makhluk.tampilkan_spesies() makhluk.buat_suara() else: print('Ini bukan mamalia.') # Fungsi main def main(): # Buat object Mamalia, object Anjing, dan object Kucing mamalia = hewan.Mamalia('Mamalia Generik') anjing = hewan.Anjing() kucing = hewan.Kucing() # Tampilkan informasi spesies satu per satu print('Berikut ini beberapa hewan dan') print('suara yang mereka buat.') tampilkan_info_mamalia(mamalia) print() tampilkan_info_mamalia(anjing) print() tampilkan_info_mamalia(kucing) print() tampilkan_info_mamalia('Saya adalah string') # Panggil fungsi main main() ``` *Output*: Berikut ini beberapa hewan dan suara yang mereka buat. Saya adalah seekor Mamalia Generik Grrrr Saya adalah seekor Anjing Guk! Guk! Saya adalah seekor Kucing Meong! Ini bukan mamalia **REFERENSI** 1] Gaddis, Tony. 2012. Starting Out With Python Second Edition. United States of America: Addison-Wesley.