Kategori
Tak Berkategori

Pemrograman Berbasis Obyek

Seluruh program yang kita tulis sejauh ini, dibuat atas dasar fungsi, yakni satu kelompok blok dari stetemen yang bertugas untuk memproses data. Pendekatan ini dinamakan procedure-oriented atau pemrograman berbasis prosedur. Ada cara lain dalam mengatur perangkat lunak Anda yakni dengan menggabungkan data dan fungsi dan menyatukannya ke dalam sesuatu yang disebut sebagai objek. Paradigma ini dinamakan pemrograman berbasis objek. Dalam banyak hal, Anda bisa menggunakan pemrograman presedural, namun saat menulis program dalam skala program, atau punya masalah yang lebih cocok dengan pendekatan ini, Anda dapat menggunakan teknik pemrograman berbasis objek.

Kelas dan objek adalah dua aspek utama dalam pemerograman berbasis objek. Sebuah kelas (class) membuat tipe (type) baru dimana objek (object) merupakan perwujudan (instance) dari sebuah kelas. Bisa dianalogikan Anda punya variabel dengan tipe int, dapat diterjemahkan bahwa variabel yang menyimpan integer tersebut merupakan variabel perwujudan dari kelas int.Catatan untuk Programmer Bahasa Statik

Perlu dicatat bahwa integer juga diperlakukan sebagai objek (dari kelas int). Hal ini berbeda di C++ dan Java (sebelum versi 1.5) di mana integer merupakan tipe bawaan awal (primitive native types). Lihat help(int) untuk informasi detail dari kelas ini.

Programmer C# dan Java 1.5 akan mengenali hal ini mirip dengan konsep boxing dan unboxing.

Objek dapat menyimpan data dengan menggunakan variabel umum yang dimiliki oleh objek tersebut. Variabel yang ikut dalam sebuah objek atau kelas sering disebut sebagai fields. Objek juga dapat digunakan dengan memanfaatkan fungsi yang dimiliki oleh sebuah kelas. Fungsi ini disebut sebagai metode/methods dari sebuah kelas. Terminologi ini penting sebab hal ini membantu kita untuk membedakan antara fungsi dan variabel yang independen dengan fungsi dan variabel yang merupakan milik dari kelas atau objek. Secara bersama-sama, fields dan methods dapat disebut sebagai atribut dari sebuah kelas.

Fields ada dua jenis – mereka ikut dalam sebuah wujud/objek dari sebuah kelas, atau mereka merupakan bagian dari kelas itu sendiri. Ini sering disebut sebagi variabel terwujud/instance variables dan variabel kelas/class variables.

Sebuah kelas dibuat dengan kata kunci class. Fields dan methods dari sebuah kelas, akan dimasukkan dalam blo yang menjorok (indented block).

Diri/Self

Metode kelas punya perbedaan khusus terhadap fungsi yang biasa Anda kenal – mereka harus punya nama depan tambahan yang harus ditambahkan di seluruh awal daftar parameter, namun Anda tidak perlu memberi nilai terhadap parameter ini saat Anda memanggil metode-nya, Python akan secara otomatis memberikannya. Variabel yang khusus ini akan merujuk pada objek itu sendiri, dan secara umum telah disepakati, dengan nama diri atau self.

Meskipun, Anda dapat memberikan nama apa saja terhadap parameter ini, namun sangat disarankan Anda menggunakan nama self – dan nama selain itu pastinya akan memancing pertanyaan. Ada keuntungan menggunakan nama yang baku – setiap pembaca program Anda akan segera mengenalinua, dan bahkan IDE (Integrated Development Environments – Alat Bantu Pengembangan yang Terintegrasi) dapat membantu jika Anda menggunakan self.Catatan untuk C++/Java/C# Programmers

self di Python sebanding dengan pointer this di C++ dan this di Java dan C#

Anda mungkin heran, kenapa Python memberikan nilai langsung untuk self dan kenapa Anda tidak perlu memberikan nilai terhadapnya. Berikut sebuah contoh yang dapat mempermudah Anda memahaminya. Misalnya Anda punya kelas dengan nama KelasKu dan perwujudan (instance) dari kelas ini dinamakan objekku. Ketika Anda memanggil metode dari objek ini dengan nama objekku.metode(argumen1, argumen2), secara otomatis akan dikonversikan oleh Python menjadi KelasKu.metode(objekku, argumen1, argumen2( – inilah yang khusus terhadap self.

Ini juga berarti jika Anda punya metode yang tidak memiliki argumen, Anda tetap harus memberikan satu arguman – self.

Kelas

Kelas yang sederhana dapat dilihat dalam contoh di bawah ini (simpan sebagai kelassederhana.py).

class Person:
    pass # blok kosong 

p = Person()
print(p)

Keluaran:

$ python3 kelassederhana.py
<__main__.Person object at 0x019F85F0>

Bagaimana Cara Kerjanya:

Kita membuat kelas baru dengan statemen class yang diikuti nama kelasnya. Kemudian di bawahnya ditambahkan statemen dalam blok yang menjorok ke dalam, sebagai isi baris perintah dari kelas tersebut. Kita menambahkan blok kosong dengan statemen pass.

Kemudian, kita membuat objek/wujud dari kelas ini dengan nama kelas yang diikuti oleh kurung kurawal. (Kita akan belajar lebih banyak tentang perwujudan/instantiation di bagian berikutnya). Sebagai verifikasi, kita konfirmasi jenis variabel tersebut sebagai sebuah objek dengan menampilkannya di layar. Informasi tersebut menunjukkan bahwa kita mempunya sebuah wujud kelas Person di dalam modul __main__.

Perhatikan bahwa alamat di mana objek Anda berada di dalam memori komputer juga dicetak. Alamat ini akan memiliki nilai yang berbeda antara apa yang muncul di layar komputer Anda dengan yang tampilan di atas, mengingat Python akan menyimpan objek di mana saja dia temukan ruangan kosong.

Metode Objek

Kita telah diskusikan bahwa kelas/objek dapat memiliki metode yang tugasnya mirip dengan fungsi (pada pemrograman prosedural), kecuali ada tambahan variabel bernama self. Kita akan lihat dalam contoh berikut (simpan dengan nama metode.py).

class Person:
    def sapaHalo(self):
        print('Halo, apa kabar?')

p = Person()
p.sapaHalo()

# Contoh di atas dapat diperpendek dengan menuliskan Person().sapaHalo()

Keluaran:

$ python3 metode.py
Halo, apa kabar?

Bagaimana Cara Kerjanya:

Di sini kita lihat bagaimana self bekerja. Perhatikan bahwa metode sapaHalo tidak membutuhkan satu parameterpun, namun dalam definisi di dalam kelasnya, masih tetap membutuhkan parameter self.

Metode init

Ada banyak nama metode yang memiliki kegunaan khusus dalam kelas di Python. Kita akan lihat pentingnya metode __init__ sebagai berikut.

Metode __init__ otomatis berjalan jika sebuah objek diwujudkan dari kelas. Metode ini berguna untuk inisialisasi hal-hal yang perlu Anda persiapkan saat objek Anda mewujud. Perhatikan bahwa di depan init ada dua garis bawah di belakang dan di depan.

Contoh (simpan sebagai class_init.py):

class Person:
    def __init__(self, nama):
        self.nama = nama
    def sapaHalo(self):
        print('Halo, nama saya', self.nama)

p = Person('Swaroop')
p.sapaHalo()

# Contoh sederhana ini juga bisa ditulis seperti ini: Person('Swaroop').sapaHalo()

Keluaran:

$ python3 class_init.py
Halo, nama saya Swaroop

Bagaimana Cara Kerjanya:

Di sini kita definisikan metode __init__ dengan mengambil nama sebagai parameter ( dan sebagaimana biasa, bersamaan dengan self). Di sini kita baru saja membuat field baru dengan nama nama. Perhatikan bahwa keduanya merupakan variabel yang berbeda meskipun keduanya sama-sama dipanggil dengan variabel nama. Hal ini bukan menjadi masalah mengingat notasi titik self.nama berarti merujuk pada sesuatu yang dipanggil “nama” dan merupakan bagian dari objek yang dipanggil dengan “self” dan variable nama lainnya merupakan variabel lokal. Mengingat kita secara eksplisit mereferensikan nama yang mana, sehingga hal ini tidak membingungkan lagi.

YAng paling penting adalah, perhatikan bahwa kita tidak secara eksplisit memanggil metode `init namun kita melemparkan arguman dalam kuruung, yang diikuti nama kelas, jika ingin membuat kelas ini mewujud dalam objek. Metode ini sangat spesifik di Python.

Sekarang, kita dapat menggunakan self.nama untuk diberikan dalam metode/fungsi, yang dalam contoh di atas bernama sapaHalo.

Kelas dan Variabel Objek

Kita telah diskusikan sebelumnya beberapa fungsi bagian dari kelas dan objek (yakni metode), sekarang kita belajar bagian yang lain, yakni data. Data di dalam objek, atau disebut field, sebenarnya merupakan variabel biasa nameun terikat lingkup nama atau name spaces dari sebuah kelas atau objek. Ini rtinya bahwa nama hanya valid di dalam konteks objek atau kelas yang bersangkutan saja. Karena itulah mereka sering disebut sebagai lingkup nama atau name spaces.

Ada dua jenis fields – variabel kelas atau variabel objek yang dikelompokkan atas dasar apakah kelas atau objek tersebut memiliki variabel tersebut.

Variabel kelas merupakan entitas yang dimanfaatkan bersama-sama – dia dapat diakses oleh seluruh perwujudan (instance) kelas yang bersangkutan. Jadi jika Anda mendefinisikan satu variabel – dia merujuk pada satu variabel yang bersangkutan, dan jika ada perubahan dilakukan oleh salah satu objek, maka perubahan tersebut akan dilihat oleh seluruh wujud objek (instances).

Variabel Objek dimiliki oleh secara tersendiri oleh objek dari kelas yang bersangkutan. Dalam hal ini, setiap objek hanya memiliki satu salinan field yang bersangkutan. Dengan kata lain field tersebut tidak akan dibagikan dan tidak berhubungan dengan field lain di objek berbeda meskipun namanya sama. Untuk mempermudah pemahaman, berikut contohnya (simpan sebagai varobjek.py):

class Robot:
    '''Mewakili sebuah robot dengan nama.'''

    # Sebuah variabl, untuk menampung hitungan jumlah robot
    populasi = 0

    def __init__(self, nama):
        '''Inisialisasi data.'''
        self.nama = nama
        print('(Inisialisasi {0})'.format(self.nama))

        # Saat robot ini dibuat, jumlah robot ditambahkan
        # ke dalam populasi
        Robot.populasi += 1

    def __del__(self):
        '''Saya mati.'''
        print('{0} sedang dimusnahkan!'.format(self.nama))

        Robot.populasi -= 1

        if Robot.populasi == 0:
            print('{0} adalah robot terakhir.'.format(self.nama))
        else:
            print('Masih ada {0:d} robot yang sedang bekerja.'.format(Robot.populasi))

    def sapaHalo(self):
        '''Ucapan salam dari salah seorang robot.
 
        Yah, tentu saja mereka dapat melakukannya.'''
        print('Salam, tuan saya memberi nama saya {0}.'.format(self.nama))

    def adaBerapa():
        '''Menampilkan jumlah populasi saat ini.'''
        print('Kita memiliki {0:d} robot.'.format(Robot.populasi))
    adaBerapa = staticmethod(adaBerapa)

droid1 = Robot('R2-D2')
droid1.sapaHalo()
Robot.adaBerapa()

droid2 = Robot('C-3PO')
droid2.sapaHalo()
Robot.adaBerapa()

print("\nPara robot dapat menjalankan beberapa tugas di sini.\n")

print("Pada robot sudah selesai menjaalankan tugas. Mari kita musnahkan mereka.")
del droid1
del droid2

Robot.adaBerapa()

Keluaran:

$ python3 varobjek.py
(Inisialisasi R2-D2)
Salam, tuan saya memberi nama saya R2-D2.
Kita memiliki 1 robot.
(Inisialisasi C-3PO)
Salam, tuan saya memberi nama saya C-3PO.
Kita memiliki 2 robot.

Para robot dapat menjalankan beberapa tugas di sini.

Para robot sudah selesai menjalankan tugas. Mari kita musnahkan mereka.
R2-D2 sedang dimusnahkan! 
Masih ada 1 robot yang sedang bekerja.
C-3PO sedang dimusnahkan!
C-3PO adalah robot terakhir.
Kita memiliki 0 robot.

Bagaimana Cara Kerjanya:

Skrip di atas merupakan contoh yang panjang, namun membantu mendemonstrasikan bagaimana sebuah variabel objek dan kelas bekerja. Di sini, populasi merupakan milik kelas Robot sehingga ini bisa kita sebut sebagai variabel kelas. Lalu variabel nama merupakan milik objek (sehingga dalam penggunaannya memakai awalan self), dan ini disebut sebagai variabel objek.

Sehingga, kita bisa menyebut variabel kelas populasi dengan sebutan Robot.populasi, dan bukan self.populasi. Kita merujuk pada variabel objek nama dengan penulisan self.nama sebagai metode di dalam objek. Mohon selalu diingat perbedaan sederhana antara variabel kelas dan variabel objek. Dan catat pula bahwa nama variabel objek yang memiliki nama yang sama dengan variabel kelas, akan menyembunyikan variabel kelas!

adaBerapa sebetulnya merupakan metode yang mengikuti kelas dan bukan objek. Ini berarti bahwa kita bisa mendefinisikannya sebagai classmethod atau sebagai staticmethod tergantung apakah kita ingin mengetahui di kelas apa kita saat ini. Mengingat kita tidak perlu mengetahui informasi tersebut, kita akan menggunakan staticmethod.

Kita dapat memperoleh hal yang sama dengan menggunakan dekorator:

@staticmethod
def adaBerapa():
    '''Menampilkan jumlah populasi saat ini.'''
    print('Kita memiliki {0:d} robot.'.format(Robot.populasi))

Dekorator dapat dibayangkan sebagai jalan pintas untuk memanggil statemen secara eksplisit, sebagaimana yang kita lihat dalam contoh.

Perhatikan bahwa metode __init__ yang digunakan untuk inisialisasi wujud Robot dengan nama. Dalam metode ini, kita meningkatkan jumlah populasi dengan tambahan 1 setelah robot ditambahkan. Juga perhatikan bahwa nilai self.nama khusus di tiap objek yang mengindikasikan cara kerja variabel objek.

Ingat, bahwa Anda harus merujuk pada variabel dan metode di dalam objek yang sama dengan hanya menggunakan awalan self. Ini dinamakan sebagai referensi atribut/attribute reference.

Dalam program ini, kita juga melihat penggunaan docstrings untuk kelas maupun metode. Kita dapat mengakses kelas docstring ini pada saat program dijalankan dengan menggunakan Robot.__doc__ dan docstring untuk metodenya dengan memanggil Robot.sapaHalo.__doc__.

Seperti metode __init__, ada metode khusus lainnya yang disebut dengan metode __del__ dan dipanggil saat objek akan dimusnahkan atau tidak akan digunakan lagi oleh komputer, sehingga kita bisa menggunakan kembali bagian dari memori komputer tersebut. Dalam metode ini kita cukup kurangi 1 nilai dari Robot.populasi.

Metode __del__ dijalankan ketika objek tidak lagi digunakan dan tidak ada garansi lagi kapan metode tersebut akan dijalankan. Jika Anda ingin melihatnya secara eksplisit, gunakan statemen del secara langsung, di mana sudah kita lakukan dalam contoh sebelumnya.

Semua anggota kelas bersifat publik. Ada satu pengecualian: Jika Anda menggunakan data dengan nama berawalan dua garis bawah seperti __varprivat, Python menggunakan penyamaran-nama secara efektif yang membuat variabel tersebut menjadi privat.

Sehingga, sudah ada ketentuan tidak tertulis yang diikuti bahwa setiap variabel yang hanya boleh digunakan dalam kelas atau objek harus diawali dengan garis bawah, selain itu dianggap sebagai publik dan dapat dimanfaatkan oleh kelas/objek yang lain. Ingat bahwa ini hanya konvensi dan tidak dipaksakan oleh Python (kecuali untuk awalan dua garis bawah).Catatan untuk Programmer C++/Java/C#

Semua anggota kelas (termasuk anggota data) bersifat publik dan seluruh metode di Python bersifat virtual.

Penurunan (Inheritance)

Salah satu keuntungan terbesar dari pemrograman berbasis objek adalah penggunaan kembali kode yang telah dibuat, dan salah satu cara melakukan ini adalah melalui mekanisme penurunan (inheritance). Penurunan dapat dibayangkan sebagai implementasi hubungan antara tipe dan sub tipe antar kelas.

Misalnya Anda ingin membuat program untuk mengatur data guru dan mahasiswa di kampus. Mereka punya karakteristik data yang sama seperti nama, usia dan alamat. Mereka juga memiliki karakteristik khusus seperti gaji dan kursus untuk guru, nilai dan uang kuliah untuk mahasiswa.

Anda dapat membuat dua kelas berbeda untuk setiap tipe dan memprosesnya sendiri-sendiri, namun jika ada tambahan tipe yang bersifat umum dan berlaku untuk kedua belah pihak, Anda harus menambahkan dua kali. Ini dapat membuat program menjadi berat dan sulit diatur.

Cara yang lebih baik adalah membuat kelas yang lebih umum, misalnya bernama AnggotaSekolah dan membuat kelas dengan nama Dosen dan Murid yang diturunkan dari kelas AnggotaSekolah. Dengan kata lain kita membuat sub tipe dari tipe (kelas) AnggotaSekolah, lalu membuat karakteristik yang khusus untuk setiap sub tipe yang kita buat ini.

Ada banyak keuntungan dari pendekatan ini. Jika kita menambahkan/mengganti fungsi di AnggotaSekolah, otomatis akan berlaku di seluruh sub tipe-nya. Misalnya Anda bisa menambah field Nomor Tanda Pengenal untuk guru dan mahasiswa, dengan menambahkannya langsung ke class AnggotaSekolah. Meskipun demikian, mengganti sub tipe tidak akan mempengaruhi sub tipe lainnya. Keuntungan lain adalah jika Anda bisa merujuk objek Dosen atau Mahasiswa sebagai objek turunan dari AnggotaSekolah adalah Anda bisa memanfaatkan data kedua sub tipe turunannya. Misalnya menghitung jumlah total guru dan mahasiswa. Ini disebut sebagai polimorfism/pholymorphism di mana setiap sub tipe dapat diganti di kondisi apapun jika tipe induk menginginkannya atau dengan kata lain objek diperlakukan sebagaimana perwujudan dari kelas induk.

Juga perhatikan bahwa penggunaan kembali kode dari kelas induknya, kita tidak perlu mengulang kembali ke dalam kelas yang berbeda sebagaimana yang kita lakukan jika kita menggunakan kelas yang independen.

AnggotaSekolah dalam hal ini disebut sebagai kelas dasar/base class atau superclass. Sementara Dosen dan Mahasiswa disebut sebagai kelas turunan/derived classes atau subclasses.

Kita akan melihat contoh ini dalam sebuah program (simpan sebagai turunan.py):

class AnggotaSekolah:
    '''Mewakili Anggota Sekolah.'''
    def __init__(self, nama, usia):
        self.nama = nama
        self.usia = usia
        print('(Inisialisasi AnggotaSekolah: {0})'.format(self.nama))

    def katakan(self):
        '''Katakan detail saya.'''
        print('Nama:"{0}" Usia:"{1}"'.format(self.nama, self.usia), end=" ")

class Dosen(AnggotaSekolah):
    '''Mewakili seorang dosen.'''
    def __init__(self, nama, usia, gaji):
        AnggotaSekolah.__init__(self, nama, usia)
        self.gaji = gaji 
        print('(Inisialisasi Dosen: {0})'.format(self.nama))

    def katakan(self):
        AnggotaSekolah.katakan(self)
        print('Gaji: "{0:d}"'.format(self.gaji))

class Mahasiswa(AnggotaSekolah):
    '''Mewakili seorang mahasiswa.'''
    def __init__(self, nama, usia, nilai):
        AnggotaSekolah.__init__(self, nama, usia)
        self.nilai = nilai 
        print('(Inisialisasi Mahasiswa: {0})'.format(self.nama))

    def katakan(self):
        AnggotaSekolah.katakan(self)
        print('Marks: "{0:d}"'.format(self.nilai))

t = Dosen('Mrs. Shrividya', 40, 30000)
s = Mahasiswa('Swaroop', 25, 75)

print() # mencetak baris kosong 

paraanggota = [t, s]
for anggota in paraanggota:
    anggota.katakan() # berjalan baik untuk Dosen maupun Mahasiswa

Keluaran:

$ python3 turunan.py
(Inisialisasi AnggotaSekolah: Mrs. Shrividya)
(Inisialisasi Dosen: Mrs. Shrividya)
(Inisialisasi AnggotaSekolah: Swaroop)
(Inisialisasi Mahasiswa: Swaroop)

Nama:"Mrs. Shrividya" Usia:"40" Gaji: "30000"
Nama:"Swaroop" Usia:"25" Gaji: "75"

Bagaimana Cara Kerjanya:

Untuk menggunakan turunan, kita tentukan dulu nama kelas dasar (_base class__) di dalam sebuah tuple diikuti dengan nama kelas pada definisi kelasnya. Kemudian, kita lihat metode __init__ dari kelas dasar yang secara eksplisit dipanggil dengan menggunakan variabel self sehingga kita dapat inisialisasi kelas dasar sebagai bagian dari objek. Sangat penting untuk diingat – Python tidak secara otomatis memanggil seluruh konstruktor kelas dasar, namun Anda harus memanggilnya sendiri.

Kita juga lihat bahwa kita dapat memanggil semua metode dalam kelas dasar dengan memberikan awalan dari nama kelas terhadap seluruh metode yang dipanggil di dalam variabel self bersamaan dengan argumen lain.

Perhatikan juga bahwa kita dapat memperlakukan wujud Dosen atau Mahasiswa sebagai perwujudan dari AnggotaSekolah ketika kita gunakan metode Katakan dari fungsi kelas AnggotaSekolah.

Perhatikan pula bahwa metode katakan dari sub tipe dipanggil,, namun bukanlah katakan dari kelas AnggotaSekolah. Satu cara untuk memahami ini adalah bahwa Python selalu memulai pencarian metode di tipe yang sedang dijalankan saat ini, yang dalam hal ini ditemukan. Jika metode tersebut tidak ketemua, ia akan mulai mencari metode yang dimiliki oleh kelas dasar satu demi satu secara urut sebagaimana yang telah ditentukan dalam tuple definisi kelas.

Satu catatan untuk terminologi – jika ada satu kelas didaftara pada tuple turuanan – ini sering disebut sebagai multiple inheritance.

Parameter end yang digunakan dalam metode katakan() untuk mengganti baris baru di akhir setiap panggilan print() untuk mencetak sesuatu.

Ringkasan

Kita telah mengeksplorasi berbagai macam aspek dari kelas dan objek dan banyak terminologi yang berkaitan dengannya. Kita juga akan lihat keuntungan dan kerugian pemrograman berbasis objek. Python sangat berorientasi terhadap objek dan memahami konsep ini secara hati-hati akan membantu Anda dalam jangka panjang.

Berikutnya, kita akan belajar bagaimana menangani input/output dan bagaimana mengakses berkas di Python.

Kategori
Python

Pemecahan Masalah

Setelah sebelumnya kita telah mengeksplorasi berbagai bagian bahasa Python, sekarang kita coba untuk menggabungkan bagian-bagian tadi menjadi satu kesatuan, dengan mendesain dan membuat program yang benar-benar berguna. Idenya adalah belajar bagaimana Anda menulis skrip Python sendiri.

Permasalahan

Permasalahan yang ingin dipecahkan adalah “Saya ingin membuat sebuah program yang membackup semua berkas-berkas saya yang penting.”.

Meskipun ini masalah sederhana, namun tidak ada informasi yang cukup bagi kita untuk mulai dengan pemecahannya. Hal ini membutuhkan sedikit analisis lanjutan. Sebagai contoh, bagaimana kita menentukan berkas mana yang penting sehingga perlu dibackup? Bagaimana berkas-berkas tersebut disimpan? Di mana tempat penyimpanannya?

Setelah menganalisis masalah tersebut secara lebih mendalam, kita mulai mendesain program kita. Kita bisa mulai dengan membuat daftar bagaimana program kita akan berjalan nantinya. Dalam kasus ini, Saya telah membuat daftar berikut tentang bagaimana Saya ingin program tersebut bekerja. Jika Anda melakukan sendiri desainnya, mungkin Anda akan membuat analisis berbeda mengingat setiap orang punya pendekatan berbeda tentang bagaimana cara mereka melakukan pekerjaannya. Dan ini sama sekali bukan masalah. Tidak apa-apa.

  • Berkas dan direktori akan disimpan dalam berkas pendukung (backup) secara khusus dalam list.
  • Berkas pendukung harus disimpan dalam direktori pendukung utama.
  • Semua berkas disimpan dalam berkas pendukung dengan format zip.
  • Penamaan dalam berkas arsip berformat zip dibuat dalam tanggal dan waktu sekarang.
  • Kita menggunakan perintah baku zip yang sudah tersedia dalam setiap distribusi Linux/Unix. Pengguna Windows dapat memasang dari Halaman Proyek GnuWin32 and add C:\Program Files\GnuWin32\bin ke dalam variabel lingkungan yang dikenal oleh PATH sistem, sama seperti cara kita mengenal perintah python sendiri. Perhatikan bahwa perintah untuk mengarsipkan berkas dapat Anda gunakan selama aplikasi tersebut tersedia dan bisa diakses melalui baris perintah.

Solusi

Mengingat desain program kita relatif sudah komplet dan stabil, sekarang kita dapat menuliskan kode sebagai implementasi dari solusi kita.

Simpan sebagai backup_ver1.py:

import os
import time

# 1. Berkas dan direktori akan disimpan dalam berkas pendukung (_back up_) secara khusus dalam list.
source = ['"C:\\My Documents"', 'C:\\Code']
# Perhatikan bahwa kita harus menggunakan petik dua di dalam string yang memiliki spasi di dalamnya.

# 2. Berkas pendukung harus disimpan dalam direktori pendukung utama.
target_dir = 'E:\\Backup' # Ingat bahwa ini harus diganti dengan direktori yang benar-benar Anda gunakan

# 3. Semua berkas disimpan dalam berkas pendukung dengan format zip.
# 4. Penamaan dalam berkas arsip berformat zip  dibuat dalam tanggal dan waktu sekarang.
target = target_dir + os.sep + time.strftime('%Y%m%d%H%M%S') + '.zip'

# 5. Kita gunakan perintah zip untuk memasukkan berkas ke dalam arsip zip
zip_command = "zip -qr {0} {1}".format(target, ' '.join(source))

# Jalankan backup
if os.system(zip_command) == 0:
    print('Backup berhasil dilakukan ke', target)
else:
    print('Backup GAGAL')

Keluaran:

$ python backup_ver1.py
Backup berhasil dilakukan ke E:\Backup\20080702185040.zip

Sekarang, kita dalam fase testing untuk menguji apakah program yang kita buat dapat berjalan dengan baik. Jika tidak berjalan sesuai harapan, kita harus melakukan debug terhadap program kita, yakni dengan memperbaiki bus (kesalahan) dari program.

Jika kode program di atas tidak berjalan, buat satu baris perintah print(zip_command) di atas baris `os.system’, dan jalankan program kembali. Kemudian, salin/tempel hasil keluaran print zip_command yang ada di layar, dan lihat apakah tulisan yang tampil sudah menunjukkan bahwa program sudah berjalan dengan benar. Jika perintah tersebut gagal, cek kembali petunjuk perintah zip dan cari kemungkinan-kemungkinan kekeliruan. Jika perintah ini berhasil dijalankan, lihat kembali program Python Anda apakah keluarannya sesuai dengan apa yang tertulis di atas.

Bagaimana Cara Kerjanya

Anda akan memahami bahwa kita telah mengonversi desain menjadi kode program langkah demi langkah.

Kita menggunakan modul os dan time dengan cara mengimpornya terlebih dahulu. Kemudian, kita tentukan berkas dan direktori yang akan dibackup ke dalam direktori yang kita namakan lewat variabel target_dir. Nama file arsip zip yang akan kita buat, terdiri dari tanggal dan waktu saat perintah tersebut dijalankan dengan menggunakan fungsi time.strftime(). Pembuatan berkas tersebut juga akan menambahkan ekstensi .zip dan akan disimpan pada direktori target_dir.

Perhatikan bahwa variabel os.sep – yang akan memberikan pemisah antar direktori yang sesuai dengan sistem operasi Anda, yakni '/' jika berada dalam lingkungan Linux dan Unix, atau '\\' di Windows dan ':' di Mac OS. Penggunaan fungsi os.sep daripada menuliskan langsung karakter pemisahnya akan membuat program kita portabel dan berjalan di sistem yang heterogen.

Fungsi time.strftime() akan mengambil karakter tertentu yang sudah ditentukan untuk kita gunakan di program di atas. Karakter spesifik %Y akan diganti dengan tahun. Sedangkan %m akan diganti nama bulan dengan format desimal antara 01 hingga 12 dan seterusnya. Spesifikasi lengkap terhadap hal ini bisa dilihat di Manual Referensi Python.

Kita membuat nama dari file arsip yang dituju dengan tambahan operator yang menggabungkan/concatenates string, yakni dengan menggabungkan dua string untuk menjadi satu string gabungan. Kemudian kita juga membuat string zip_command yang berisi seluruh perintah yang akan kita eksekusi. Anda dapat mengecek apakah perintah ini berjalan atau tidak dengan menjalankannya di shell (baik di terminal Linux atau prompt DOS).

Perintah zip yang kita gunakan memiliki opsi dan parameter yang bisa dimasukkan. Opsi -q digunakan sebagai indikasi bahwa perintah zip haraus berjalan secara diam-diam (quietly). Opsi -r menunjukkan bahwa perintah zip harus dijalankan secara rekursif di dalam direktori, yakni dengan memasukkan seluruh sub direktori dan berkas di bawahnya. Kedua parameter tersebut dapat digabung menjadi satu parameter -qr. Opsi tersebut diikuti nama berkas arsip zip yang didalamnya akan diisi arsip seluruh berkas dan direktori yang akan dibackup. Kita mengonversi list source menjadi string lewat metode yang sudah pernah kita lihat penggunaannya sebelumnya, yakni join string.

Lalu kita benar-benar menjalankan perintah tersebut lewat fungsi os.system di mana fungsi tersebut akan menjalankan perintah seolah-olah dijalankan oleh sistem, yakni akan memberikan kembalian 0 jika berhasil, dan jika gagal akan memberikan nomor pesan kesalahan yang sesuai dengan sistem operasinya.

Tergantung dari keluaran perintah di atas, kita akan mencetak pesan pelaksanaan backup tersebut apakah gagal atau berhasil.

Itu saja, kita telah membuat skrip untuk membackup seluruh berkas-berkas penting kita!Catatan untuk pengguna Windows

Selain menggunakan backslash (garis miring kiri) untuk lepas dari urutan (sequences), Anda bisa menggunakan string dasar. Sebagai contoh 'C:\\Documents' atau r'C:\Documents'. Meskipun demikian jangan menggunakan 'C:\Documents' karena nantinya akan dianggap sebagai string urutan lepas (escape sequence\D.

Sekarang kita sudah memiliki skrip backup yang berjalan dengan baik, dan kita bisa menggunakannya setiap saat kita butuhkan untuk membuat backup berkas. Pengguna Linux/Unix sangat disarankan untuk menggunakan metode yang bisa dieksekusi sebagaimana yang telah kita diskusikan sebelumnya, sehingga kita dapat menjalankan skrip backup kapan saja dan di mana saja. Hal ini sering disebut fase operasi atau fase deployment dari sebuah perangkat lunak.

Meskipun program di atas dapat berjalan sebagaimana mestinya, tapi (biasanya) program pertama kali dijalankan tidak sesuai dengan yang diinginkan. Sebagai conth, mungkin akan ada masalah jika Anda tidak mendesain program dengan layak, atau Anda melakukan kesalahan saat mengetikkan kode sintaks, dan sebagainya. Selayaknya, kita harus kembali ke fase desain atau nanti Anda harus debug program yang Anda buat.

Versi Kedua

Versi pertama dari program yang kita buat telah berjalan sebagaimana mestinya. Meskipun demikian, kita bisa saja membuat beberapa perbaikan sehingga dapat berjalan lebih baik setiap harinya. Ini disebut sebagai fase pemeliharaan dari pengembangan perangkat lunak.

Salah satu perbaikan yang saya pikir akan berguna lebih baik adalah mekanisme penamaan berkas – dengan menggunakan waktu sebagai bagian dari nama berkas di dalam direktori backup utama. Keuntungan pertama adalah, backup Anda akan disimpan dalam format yang hierarkis sehingga lebih mudah untuk diatur. Keuntungan kedua, nama berkas jauh lebh pendek. Keuntungan ketiga, direktori yang terpisah akan membantu Anda jika Anda mambuat backup tiap hari, dan direktori yang terbuat adalah direktori yang memang benar-benar dibuat di hari itu.

Simpan sebagai backup_ver2.py:

import os
import time

# 1. Berkas dan direktori yang dibackup disebut secara khusus dalam daftar(_list_).
sumber = ['"C:\\My Documents"', 'C:\\Code']
# Perhatikan bahwa kita menggunakan tanda petik dua di dalam string untuk nama yang memiliki spasi.

# 2. Backup harus disimpan di dalam direktori backup utama
target_dir = 'E:\\Backup' # Mohon diingat untuk ganti ini dengan folder yang akan Anda gunakan

# 3. Berkas akan dibackup ke dalam berkas zip.
# 4. Nama sub direktori dengan nama hari ini di dalam direktori utama 
today = target_dir + os.sep + time.strftime('%Y%m%d')
# Waktu hari ini adalah nama dari arsip zip 
now = time.strftime('%H%M%S')

# Buat sub direktori jika belum ada di sana 
if not os.path.exists(today):
    os.mkdir(today) # make directory
    print('Berhasil membuat direktori', today)

# Nama berkas zip 
target = today + os.sep + now + '.zip'

# 5. Sekarang kita gunakan perintah zip untuk memasukkan berkas ke dalam arsip zip
zip_command = "zip -qr {0} {1}".format(target, ' '.join(source))

# Jalankan backup 
if os.system(zip_command) == 0:
    print('Berhasil backup ke dalam ', target)
else:
    print('Backup GAGAL')

Keluaran:

$ python3 backup_ver2.py
Berhasil membuat direktori E:\Backup\20080702
Berhasil backup ke dalam E:\Backup\20080702\202311.zip

$ python3 backup_ver2.py
Berhasil backup ke dalam E:\Backup\20080702\202325.zip

Bagaimana Cara Kerjanya

Hampir sebagian besar program sama dengan yang sebelumnya. Perbedaannya hanya ketika saat kita mengecek apakah sudah ada direktori yang namanya sama dengan nama hari ini di dalam direkotri backup utama dengan fungsi os.path.exists. Jika tidak ada, kita akan buat direktori dengan fungsi os.mkdir

Versi Ketiga

Versi kedua berjalan baik saat saya melakukan backup, tapi saat ada banyak berkas yang perlu dibackup, saya kesulitan untuk membedakan berkas-berkas yang saya backup! Misalnya saya membuat perubahan besar dalam program atau presentasi, lalu saya ingin mengasosiasikan perubahan tersebut dalam nama berkas atau nama arsip zip. Ini dapat diperoleh dengan mudah dengan memberikan komentar ddi dalam nama berkas arsip zip-nya.Catatan

Program berikut ini tidak akan jalan, jadi tidak perlu khawatir. Mohon ikuti karena ada pelajaran di sini.

Simpan sebagai backup_ver3.py:

import os
import time

# 1. Berkas-berkas dan direktori akan dibackup dalam list 
sumber = ['"C:\\My Documents"', 'C:\\Code']
# Perhatikan bahwa kita menggunakan petik dua di dalam string untuk nama yang memiliki spasi.

# 2. Backup harus disimpan dalam direktori backup utama 
target_dir = 'E:\\Backup' # Ingat untuk mengganti ini dengan direktori yang akan Anda gunakan

# 3. Berkas akan dibackup dalam format zip
# 4. Hari ini adalah nama sub direktori di bawah direktori utama

hari_ini = target_dir + os.sep + time.strftime('%Y%m%d')
# Waktu sekarang digunakan sebagai nama dalam arsip zip
sekarang = time.strftime('%H%M%S')

# Simpan komentar dari pengguna untuk membuat nama yang digunakan dalam berkas zip
komentar = input('Masukkan komentar --> ')
if len(komentar) == 0: # cek apakah komentar sudah diisikan
    target = hari_ini + os.sep + sekarang + '.zip'
else:
    target = hari_ini + os.sep + sekarang + '_' +
        komentar.replace(' ', '_') + '.zip'

# Buat sub direktori dulu jika belum ada
if not os.path.exists(hari_ini):
    os.mkdir(hari_ini) # membuat direktori 
    print('Berhasil membuat direktori ', hari_ini)

# 5. Selanjutnya kita gunakan perintah zip untuk memasukkan berkas ke dalam arsip zip
zip_command = "zip -qr {0} {1}".format(target, ' '.join(sumber))

# Jalankan backup 
if os.system(zip_command) == 0:
    print('Berhasil membuat backup di ', target)
else:
    print('Backup GAGAL')

Keluaran:

$ python3 backup_ver3.py
  File "backup_ver3.py", line 25
    target = hari_ini + os.sep + sekarang + '_' +
                                        ^
SyntaxError: invalid syntax

Kenapa ini (tidak) Berjalan:

Program ini tidak berjalan! Python mengatakan ada kesalahan sintaks, yang berarti bahwa skirp tidak sesuai dengan struktur yang diharapkan oleh Python. Ketika kita melihat pesan kesalahan yang diberikan oleh Python, pesan tersebut juga mengatakan di mana sebetulnya letak kesalahannya. Jadi kita memulai proses debugging untuk pemecahan masalah dari program kita di baris tersebut.

Saat melihat lebih dalam, kita lihat ada satu baris yang secara fisik satu, namun dipisah menjadi dua baris, namun kita tidak menetukan bahwa dua baris yang berbeda ini merupakan satu kesatuan. Pada dasarnya, Python telah menemukan bahwa operator tambahan (+) tanpa operand dalam baris tersebut, sehingga tidak tahu bagaimana harus melanjutkan. Ingat bahwa kita bisa menentukan satu bagis logis di dalam dua baris fisik namun tetap menjadi satu kesatuan. Jadi kita akan perbaiki program kita. Perbaikan program saat kita menemukan pesan kesalahan semacam ini dinamakan bug fixing.

Versi ke Empat

Simpan sebagai backup_ver4.py:

import os
import time

# 1. Berkas-berkas dan direktori akan dibackup dalam list 
sumber = ['"C:\\My Documents"', 'C:\\Code']
# Perhatikan bahwa kita menggunakan petik dua di dalam string untuk nama yang memiliki spasi.

# 2. Backup harus disimpan dalam direktori backup utama 
target_dir = 'E:\\Backup' # Ingat untuk mengganti ini dengan direktori yang akan Anda gunakan

# 3. Berkas akan dibackup dalam format zip
# 4. Hari ini adalah nama sub direktori di bawah direktori utama

hari_ini = target_dir + os.sep + time.strftime('%Y%m%d')
# Waktu sekarang digunakan sebagai nama dalam arsip zip
sekarang = time.strftime('%H%M%S')

# Simpan komentar dari pengguna untuk membuat nama yang digunakan dalam berkas zip
komentar = input('Masukkan komentar --> ')
if len(komentar) == 0: # cek apakah komentar sudah diisikan
    target = hari_ini + os.sep + sekarang + '.zip'
else:
    target = hari_ini + os.sep + sekarang + '_' + \
        komentar.replace(' ', '_') + '.zip'

# Buat sub direktori dulu jika belum ada
if not os.path.exists(hari_ini):
    os.mkdir(hari_ini) # membuat direktori 
    print('Berhasil membuat direktori ', hari_ini)

# 5. Selanjutnya kita gunakan perintah zip untuk memasukkan berkas ke dalam arsip zip
zip_command = "zip -qr {0} {1}".format(target, ' '.join(sumber))

# Jalankan backup 
if os.system(zip_command) == 0:
    print('Berhasil membuat backup di ', target)
else:
    print('Backup GAGAL')

Keluaran:

$ python3 backup_ver4.py
Masukkan komentar --> tambah contoh baru 
Berhasil membuat backup di E:\Backup\20080702\202836_tambah_contoh_baru.zip

$ python3 backup_ver4.py
Masukkan komentar -->
Berhasil membuat backup di E:\Backup\20080702\202839.zip

Bagaimana Cara Kerjanya

Sekarang program ini berjalan sesuai dengan yang kita harapkan! Mari kita lihat bersama, di sebelah mana yang kita perbaiki dari versi 3. Kita meminta komentar/masukan dengan menggunakan fungsi input, kemudian kita cek kembali apakah pengguna memasukkan komentar sesuai dengan panjang yang kita tentukan lewat fungsi len. Jika pengguna menekan tombol enter tanpa memasukkan apapun (mungkin hanya backup rutin atau tidak ada perubahan berkasnya), kita langsung memproses sesuai langkah yang telah kita lakukan sebelumnya.

Meskipun demikian, jika ada komentar yang dituliskan, komentar ini akan dimasukkan ke dalam nama berkas, sebelum ekstensi .zip. Perhatikan bahwa kita mengganti spasi yang ada dalam komentar dengan garis bawah _. Alasannya adalah karena lebih mudah mengatur berkas-berkas dengan nama tanpa spasi.

Perbaikan Lebih Lanjut

Versi ke empat merupakan skrip yang berjalan secara memuaskan bagi banyak pengguna, namun selalu ada ruang untuk perbaikan. Sebagai contoh, Anda dapat menambahkan level verbosity (lebih banyak kata/informasi yang ditampilkan oleh skrip) dengan menambahkan opsi -v agar program Anda lebih berbicara.

Kemungkinan perbaikan lainnya misalkan dengan memperbolehkan berkas-berkas tambahan dan direktori untuk diumpankan pada baris perintah. Kita dapat memperoleh informasi pilihan kata yang diumpankan ini lewat fungsi sys.argv yang berupa list, sehingga kita dapat menambahkan metode extend yang telah diberikan oleh class list.

Perbaikan terbaik yang bisa Anda lakukan adalah dengan tidak menggunakan cara os.system untuk membuat berkas arsip, namun menggunakan modul yang secara baku sudah ada, yakni zipfile atau tarfile. Keduanya merupakan bagian dari pustaka standar dan langsung tersedia tanpa memerlukan dependensi program zip eksternal yang mengharuskan program zip tersedia terlebih dahulu di komputer Anda.

Namun, saya menggunakan cara os.system dalam membuat backup di program di atas untuk kepentingan pembelajaran, sehingga contoh yang diberikan cukup sederhana untuk dipahami oleh setiap orang, namun juga nyata karena dapat dijalankan untuk diambil manfaatnya.

Dapatkah Anda coba membuat versi ke lima yang menggunakan modul zipfile daripada fungsi sistem os.system?

Proses Pengembangan Perangkat Lunak

Kita telah melakukan beberapa fase dalam proses pengembangan perangkat lunak. Fase ini dapat diringkas sebagai berikut:

  1. Apa (Analisis)
  2. Bagaimana (Desain)
  3. Mengerjakan (Implementasi)
  4. Uji coba (Uji coba dan debugging)
  5. Menggunakan (Operasi atau Pemasangan)
  6. Perawatan (Perbaikan terus menerus)

Salah satu prosedur menulis perangkat lunak yang direkomendasikan sudah kita ikuti satu demi satu dalam membuat skrip backup sebelumnya: Dimulai dengan analisis dan desain. Lalu Mulai dengan implementasi untuk program yang sederhana. Kemudian kita lakukan ujicoba dan debug. Kita gunakan programnya agar berjalan sesuai dengan yang diharapkan. Sekarang, kita menambahkan fitur-fitur yang diinginkan, kemudian melakukan kembali proses dari siklus Kerjakan-Ujicoba-Gunakan sebanyak yang dibutuhkan. Ingat bahwa Perangkat lunak tidak tumbuh, namun dibangun.

Ringkasan

Kita telah melihat bagaimana membuat program/skrip Python kita sendiri, dan berbagai tahapan yang dibutuhkan dalam menulis sebuah perangkat lunak. Anda mungkin dapat memanfaatkannya untuk menulis program Anda sendiri sebagaimana yang sudah Anda kerjakan di bab ini hingga Anda nyaman dengan Python sebagaimana Anda nyaman dengan pemecahan-masalah.

Selanjutnya, kita akan diskusikan pemrograman berbasis-objek.