Kamis, 17 Juni 2010

Karena ada rekan blogger yang Requet tentang tutorial python,saya akhirnya ingin membagi ilmu buat rekan-rekan yang masih awam tentang bahasa program ini,Bagian tutorial kali ini akan membahas masalah seputar objek.

Objek

Python tentu saja mendukung pemrograman berorientasi objek. Bahkan, nyaris segala sesuatu di Python���mulai dari string, angka, fungsi���adalah objek. Apakah objek itu? Objek adalah sesuatu yang menampung nilai/data dan dapat kita kenakan operasi tertentu. Di dunia nyata ini, banyak hal yang bisa kita sebut objek. Buku misalnya, merupakan objek karena menampung informasi dan dapat kita baca (kenakan operasi baca) atau tulis (kenakan operasi tulis). Sepeda, binatang, manusia, semua juga bisa disebut objek.

>>> "aku seorang kapiten".split(" ")
['aku', 'seorang', 'kapiten']

Pada contoh di atas, kita membuat objek string bernilai ���aku seorang kapiten��� lalu mengenakan operasi split() pada objek string tersebut, yaitu dengan sintaks titik diikuti oleh nama operasi (yang disebut metode objek). Hasilnya adalah sebuah list���yang merupakan objek juga. List ini berisi 3 elemen, masing-masing elemennya adalah string yang telah dipecah (yang, lagi-lagi, merupakan objek pula). Sehingga lewat operasi split() kita telah menciptakan empat objek baru, sebuah list dan tiga buah string.

Catatan: Perhatikan bahwa kode di atas hanya akan berjalan di Python versi 2 ke atas. Di versi 1.5.2 dan sebelumnya, Python belumlah ���semurni��� sekarang, dan belum memperlakukan tiap jenis objek secara konsisten. Untuk contoh selanjutnya, diasumsikan Anda telah menggunakan Python 2.

>>> kata = "aku seorang kapiten".split(" ")
>>> kata.append("mempunyai")
>>> kata.append("pedang")
>>> kata.append("panjang")
>>> kata
['aku', 'seorang', 'kapiten', 'mempunyai', 'pedang', 'panjang']
>>> kata.sort()
>>> kata
['aku', 'kapiten', 'mempunyai', 'panjang', 'pedang', 'seorang']

Pada contoh di atas, kita mula-memberi nama objek list hasil split()dengan variabel kata. Kita lalu mengenakan operasi append() pada kata. Operasi append() adalah operasi pada objek list yang berguna untuk menambah satu elemen di akhir list. Setelah tiga kali menambah elemen, kita meminta Python mencetak isi objek list kita. Setelah itu kita mengenakan lagi operasi sort() pada objek kita. Hasilnya adalah keenam kata yang telah diurutkan secara alfabetis.

Memberi nilai dan mengenakan operasi pada objek di Python mudah bukan? Apakah ada jenis objek lain selain string dan list? Tentu saja. Dictionary, float (bilangan desimal), dan int (bilangan bulat) semuanya adalah objek. Perhatikan contoh-contoh berikut:

>>> {'tomi':'taurus', 'vira':'virgo', 'santi':'sagitarius'}.keys()
['tomi', 'vira', 'santi']
>>> {'tomi':'taurus', 'vira':'virgo', 'santi':'sagitarius'}.values()
['taurus', 'virgo', 'sagitarius']
>>> (-1.3).__abs__()
1.3

Perhatikan bahwa pada kasus terakhir, kita perlu memberi tanda kurung dulu sebelum memberi titik dan nama operasi, agar parser Python tidak kebingungan���ingat bahwa sebuah bilangan desimal juga dapat mengandung karakter titik. Contoh terakhir juga dapat ditulis secara ���non-OO��� yaitu abs(-1.3) dan akan memberi hasil yang sama.
Refleksi: Fungsi dir()

Kalau Anda menjumpai sebuah objek, bagaimana kita tahu apa saja yang kita bisa lakukan terhadapnya? Dengan kata lain, operasi apa saja yang berlaku untuk objek tersebut? Kalau Anda sedang memakai bahasa level rendah seperti C++ maka jawabannya barangkali: teliti source codenya untuk mengetahui ini objek jenis apa, lalu teliti source code lagi untuk mengetahui definisi objeknya atau baca manual untuk mengetahui daftar metode untuk jenis objek yang dimaksud. Tapi di bahasa level tinggi seperti Python (atau Ruby atau Smalltalk), ada cara yang jauh lebih mudah: bertanyalah langsung. Bahasa-bahasa ini sangat terbuka dan mengizinkan kita mengintip ke dalam tiap objek untuk mengetahui isi perutnya. Istilah yang umum dipakai untuk urusan intip-mengintip ini adalah refleksi���yang berarti melihat bayangan diri sendiri, seperti melihat di cermin. Mari kita lihat seperti apa kemampuan refleksi di Python.

Fungsi yang perlu Anda ketahui paling pertama yaitu dir(). Fungsi dir() akan mengambil informasi dari objek dan memberitahu kita daftar atribut/operasi yang tersedia untuk suatu objek. Contoh:

>>> dir("")
['__add__', '__class__', '__contains__', '__delattr__', '__doc__', '__eq__',
'__ge__','__getattribute__', '__getitem__', '__getslice__', '__gt__',
'__hash__', '__init__', '__le__', '__len__', '__lt__', '__mul__', '__ne__',
'__new__', '__reduce__', '__repr__', '__rmul__', '__setattr__', '__str__',
'capitalize', 'center', 'count', 'decode', 'encode', 'endswith',
'expandtabs', 'find', 'index', 'isalnum', 'isalpha', 'isdigit', 'islower',
'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip',
'replace', 'rfind', 'rindex', 'rjust', 'rstrip', 'split', 'splitlines',
'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper']

Pada contoh di atas kita bertanya pada Python, objek string ("") itu mengandung atribut/mendukung operasi apa saja? dir() akan mengembalikan list berisi informasi yang dimaksud. Hm, ada upper() dan lower(). Mari kita coba.

>>> "Prok, Prok, Prok!".upper()
'PROK, PROK, PROK!'
>>> "Prok, Prok, Prok!".lower()
'prok, prok, prok!'

Mudah sekali bukan? Kita tidak perlu melihat manual untuk mengetahui bagaimana cara mengkonversi sebuah string menjadi huruf kapital atau huruf kecil. Cukup buatlah objek, menanyakan jenis-jenis operasi pada Python, lalu memanggil metode yang sesuai.

Tapi tentu tidak semua semudah itu. Beberapa operasi/metode membutuhkan argumen. Bagaimana kita mengetahui sintaks setiap operasi?

Lagi-lagi refleksi Python membantu. Kita dapat mengintip atribut __doc__ sebuah objek untuk mengetahui keterangan singkat mengenai objek tersebut. Rata-rata objek memiliki atribut __doc__ yang disebut docstring ini. Misalnya,

>>> "tes".replace.__doc__
'S.replace (old, new[, maxsplit]) -> string\n\nReturn a copy of string S with
all occurrences of substring\nold replaced by new. If the optional argument
maxsplit is\ngiven, only the first maxsplit occurrences are replaced.'

Pada contoh di atas, kita ingin mengetahui sintaks metode replace() pada objek string. Perhatikan bahwa kita tidak menambahkan tanda kurung, (), setelah replace, menandakan bahwa kita bukan ingin memanggil metode objek replace() ini, melainkan mengambil atribut __doc__-nya. "tes" adalah sebuah objek berjenis string, dan "tes".replace adalah juga sebuah objek berjenis fungsi/metode. Jika kita menambahkan () setelah menyebutkan fungsi, maka kita mengenakan operasi memanggil atau mengeksekusi objek fungsi tersebut. Apakah "tes".replace.__doc__ sebuah objek juga? Ya, sebuah string.

Kembali ke __doc__. Sewaktu kita meminta nilai "tes".replace.__doc__ pada Python, Python memberikan nilai mentahnya. Buktinya, bisa Anda lihat kode escape \n yang terkandung di dalamnya. Bagaimana agar \n benar-benar tercetak sebagai newline? Mudah saja, print-lah docstring tersebut.

>>> print "tes".replace.__doc__
S.replace (old, new[, maxsplit]) -> string

Return a copy of string S with all occurrences of substring
old replaced by new. If the optional argument maxsplit is
given, only the first maxsplit occurrences are replaced.

Lebih enak dibaca bukan? Dari docstring ini kita mengetahui bahwa metode replace() membutuhkan dua atau tiga argumen. Argumen pertama, old, adalah string yang ingin diganti oleh argumen kedua, new. Sementara argumen ketiga yang bersifat opsional menyatakan jumlah penggantian maksimum yang boleh dilakukan. Mari praktikkan.

>>> "kadal".replace("l","k").replace("a","o")
'kodok'
>>> "kadal".replace("l","k").replace("a","o",1)
'kodak'

Contoh pertama mula-mula mengganti huruf ���l��� dengan huruf ���k��� pada objek string ���kadal���, sehingga menghasilkan objek string baru bernilai ���kadak���. Objek baru ini langsung dioperasi lagi dengan replace() kedua sehingga semua ���a���-nya menjadi ���o���. Sehingga hasil akhirnya menjadi ���kodok���. Contoh kedua sama, tapi menggunakan argumen ketiga pada replace() kedua.

Silakan Anda bermain-main dengan dir() dan mengintip apa saja yang bisa dilakukan terhadap objek-objek Python. Cobalah perintah-perintah berikut di interpreter interaktif Python dan telitilah lebih lanjut tiap atribut yang dikembalikan oleh dir(). Jika Anda butuh, cetaklah atribut __doc__-nya.

>>> dir(1)
>>> dir({})
>>> dir([])
>>> dir(None)
>>> dir(dir)
>>> import os
>>> dir(os)
>>> print os.rename.__doc__


>>> _

Kelas

Setelah puas bermain-main dengan objek yang ada di Python, Anda mungkin kini bertanya: bisakah saya membuat jenis objek saya sendiri? Jawabnya: tentu bisa, dengan bantuan objek khusus bernama kelas. Kelas adalah objek yang kita pakai untuk membuat objek lain. Kelas di Python didefinisikan dengan kata kunci class. Contoh definisi kelas paling sederhana:

class Titik:
pass

Kelas Titik kita adalah kelas kosong yang siap dipakai untuk membuat objek. Bagaimana cara membuat objek dari kelas? Jawabnya: dengan menggunakan (), dengan kata lain memanggil kelas tersebut.

titikku = Titik()

Maka jadilah sebuah objek kosong. Objek ini memiliki tipe Titik, dan disebut juga sebagai instans dari Titik. Cobalah mencetak nilainya di interpreter interaktif Python:

>>> titikku = Titik()
>>> titikku
<__main__.titik>

Python memberitahu bahwa titikku berisi objek yaitu instans dari kelas Titik. Apa yang bisa kita lakukan dengan objek ini? Kita bisa mengisinya dengan atribut atau nilai.

titikku.x = 5
titikku.y = 10

Objek titikku di sini dapat Anda pandang sebagai kantung atau namespace yang Anda isi dengan atribut-atribut bernama dan bernilai. Dan bisa juga Anda padang sebagai dictionary. Bahkan, sebetulnya, atribut-atribut ini memang disimpan oleh Python di sebuah atribut dictionary khusus bernama __dict__.
Refleksi: __dict__

Selain __doc__, ada satu atribut objek spesial lain yang disebut __dict__. __dict__ ini adalah sebuah dictionary yang dipakai Python untuk menyimpan daftar atribut pada objek bersangkutan. Objek-objek seperti modul dan instans kelas dapat Anda intip __dict__-nya untuk mengetahui atribut apa saja yang ada di dalamnya. Contoh:

>>> import os
>>> dir(os)
>>> print os.__dict__

Kalau Anda perhatikan keluarannya, maka dir() dan __dict__ akan memberikan hasil yang mirip-mirip.

Untuk apa __dict__? Dengan __dict__ kita dapat memanipulasi daftar atribut sebuah objek atau mengambil atribut sebuah objek secara dinamik. Contohnya:

>>> for cmd in ['setuid','open','stat']:
... print cmd
... print os.__dict__[cmd].__doc__
... print
...
setuid
setuid(uid) -> None
Set the current process's user id.

open
open(filename, flag [, mode=0777]) -> fd
Open a file (for low level IO).

stat
stat(path) -> (st_mode, st_ino, st_dev, st_nlink, st_uid, st_gid,
st_size, st_atime, st_mtime, st_ctime)
Perform a stat system call on the given path.

>>> _

Pada contoh di atas, kita mencetak docstring dari ketiga fungsi yang terdapat di modul os (yang telah kita import sebelumnya, tentu saja). Tapi alih-alih menggunakan sintaks os.open.__doc__, kita menggunakan os.__dict__['open'].__doc__. Keduanya setara, tapi dengan menggunakan dictionary __dict__, kita dapat menyebutkan atribut objek dengan nama variabel. Dengan __dict__ kita juga mencari sebuah atribut dari program kita. Bahkan kita dapat menghapus atribut objek dengan memanipulasi isi __dict__. Ingat, __dict__ adalah sebuah objek dictionary, dan kita bisa melakukan operasi sebagaimana kita memanipulasi sebuah dictionary biasa.

Kembali ke objek titikku kita sebelumnya:

>>> titikku = Titik()
>>> titikku.__dict__
{}

Saat pertama kita cetak, __dict__ dari objek titikku masih kosong karena belum ada atribut apa-apa pada objek kita tersebut. Tapi setelah kita melakukan:

>>> titikku.x = 5
>>> titikku.y = 10
>>> titikku.__dict__
{'y': 10, 'x': 5}

Maka __dict__ pun berisi atribut yang telah kita isikan sebelumnya. Jadi bisa Anda lihat bukan? Dengan mengintip atribut __dict__ pada sebuah objek instans kelas, kita dapat melakukan refleksi terhadap objek tersebut. Kita dapat mengetahui atribut-atribut apa yang terkandung dalam objek kita. Bahkan, seperti telah disebutkan sebelumnya, kita dapat menambah atau menghapus atribut objek lewat __dict__ ini.

>>> titikku.__dict__['x'] = 7
>>> titikku.x
7
>>> titikku.__dict__['z'] = -3
>>> titikku.z
-3
>>> del titikku.__dict__['y']
>>> titikku.__dict__
{'x': 7, 'z': -3}
>>> titikku.y
Traceback (most recent call last):
File "", line 1, in ?
AttributeError: Titik instance has no attribute 'y'
>>> _

Pada contoh di atas, kita menambahkan elemen ���z��� pada atribut __dict__ sehingga titikku.z dikenali. Lalu kita menghapus atribut ���y��� sehingga titikku tidak lagi memiliki atribut tersebut.

Mari kita kembali kepada dir(). Apa yang akan dilaporkan oleh dir() untuk objek titikku?

>>> dir(titikku)
['__doc__', '__module__', 'x', 'z']

Kenapa sudah ada dua atribut, __doc__ dan __module__, di situ? Padahal kita tidak pernah membuat atau mengisinya bukan? Ingat, atribut-atribut yang memiliki sintaks __NAMA__ adalah atribut spesial. __doc__, misalnya, sebetulnya diambil dari source code program. Coba cetak nilainya:

>>> titikku.__doc__
>>> _

Ternyata kosong. Tapi jika kita mendefinisikan kelas Titik seperti ini:

class Titik:
"Membuat sebuah objek titik."
pass

Maka jika kita membuat instans Titik lagi:

>>> titikku=Titik()
>>> titikku.__doc__
'Membuat sebuah objek titik.'

maka __doc__ secara ajaib telah terisi. Ya. __doc__, sesuai namanya, akan diisi oleh Python dengan string pertama pada sebuah definisi kelas atau fungsi. Programer Python biasanya menaruh dokumentasi singkat di dalam string ini. Sehingga jika ingin melihatnya nanti bisa dengan mudah mengintip __doc__. Python akan mengambilkan nilai string ini untuk Anda. Cobalah mengintip ke dalam file os.py (lokasinya di /usr/lib/python2.2/os.py atau bisa berbeda di sistem Anda). Maka Anda akan dapat melihat banyak docstring yang nantinya bisa Anda lihat lagi dari Python dengan mengakses __doc__. Refleksi yang satu ini amat mempermudah kita dalam mengekstrak dokumentasi dari program Python itu sendiri.

Catatan: pass pada definisi kelas Titik di atas boleh ada atau tidak. Pada kasus sebelumnya wajib ada karena Python membutuhkan minimal satu statement untuk definisi kelas.
Metode Objek

Sampai sejauh ini objek titik kita���meski bisa diisi atribut apa saja���tetap saja agak-agak garing karena tidak bisa kita apa-apakan lagi. Dengan kata lain, tidak ada operasi yang tersedia untuk objek kita ini. Bagaimana caranya mendefinisikan operasi untuk jenis objek kita? Jawabnya: dengan mendefinisikan fungsi di dalam definisi kelas. Definisikan kembali kelas Titik kita sbb.:

class Titik:
"Titik yang dapat dipindah-pindahkan."

def __init__(self, initialX, initialY):
self.x = initialX
self.y = initialY

def move(self, amountX, amountY):
"""move(amountX, amountY) -> None

Pindahkan titik sebanyak amountX ke kanan, amountY ke atas."""
self.x += amountX
self.y += amountY

def whereami(self):
print "Aku ada di (%d, %d)" % (self.x, self.y)

Ada beberapa hal yang perlu diperhatikan. Pertama, kita mendefinisikan dua operasi bagi instans kelas Titik, yaitu move() dan whereami() dan sebuah operasi khusus __init__() untuk menginisialisasi atribut-atribut awal objek. Kedua, __init__() tidak dipanggil manual, tapi akan dipanggil saat kita membuat objek Titik(). Ketiga, perhatikan bahwa argumen pertama semua metode ini adalah self. Python memang menyisipkan instans kelas kita nanti di argumen pertama, agar tiap fungsi/metode ini dapat mengakses isi instans kelas. Waktu kita memanggil metode dengan sintaks obj.namametode(a, b, c) nanti, self tidak perlu disebutkan lagi karena akan dimasukkan secara otomatis oleh Python menjadi obj.namametode(obj, a, b, c). Empat, perhatikan pula kita memberi docstring pada kelas Titik (docstring satu baris) dan pada metode move() (docstring banyak baris/multiline).

Setelah kelas Titik didefinisikan, mari membuat instansnya. Karena terdapat __init__ yang menerima dua argumen (di luar self), maka kita dapat membuat instans objek Titik dengan cara:

>>> t = Titik(5, 10)

Andaikata tidak ada __init__(), kita tetap dapat membuat sebuah titik yang berlokasi awal di koordinat (5, 10) dengan cara:

>>> t = Titik()
>>> t.x = 5
>>> t.y = 10

Jadi kegunaan __init__() adalah sebagai notasi ringkas inisialisasi objek.

Mari kita coba menggunakan metode-metode objek kita:

>>> t.whereami()
Aku ada di (5, 10)
>>> t.move(1,1)
>>> t.whereami()
Aku ada di (6, 11)
>>> t.move(-1,1)
>>> t.whereami()
Aku ada di (5, 12)

Akhirnya, titik kita sudah lebih keren sekarang. Bisa dipindah-pindahkan dengan operasi buatan sendiri.
Refleksi Lagi

Apakah kita bisa mengintip objek kelas Titik maupun instans-instansnya dengan fasilitas refleksi? Tentu saja. Berikut contoh-contohnya.

>>> t=Titik(5, 10)
>>> dir(Titik)
['__doc__', '__init__', '__module__', 'move', 'whereami']
>>> dir(t)
['__doc__', '__init__', '__module__', 'move', 'whereami', 'x', 'y']
>>> t.__doc__
'Titik yang dapat digerak-gerakkan.'
>>> t.move.__doc__
'move(amountX, amountY) -> None\n\n Pindahkan titik sebanyak
amountX ke kanan, amountY ke atas.'
>>> t.__dict__
{'y': 10, 'x': 5}
>>> t.__dict__['x'] = 10
>>> t.__dict__['y'] = 1
>>> t.move(-5, 9)
>>> t.__dict__
{'y': 10, 'x': 5}
>>> _

Penutup

Pada kesempatan lain kita akan lebih jauh membahas mengenai metode dan paradigma OO seperti pewarisan. Sementara itu, Anda bisa mencoba sebuah modul standar bernama inspect. Modul ini membantu kita melakukan refleksi dengan lebih praktis. Bagaimana cara menggunakan modul ini? Anda bisa membaca manual Python atau��� terlebih dahulu mengintip modul inspect ini dengan refleksi yang disediakan Python! Selamat berefleksi. (sh)

0 komentar:

Posting Komentar

Mohon Tidak Mengirim Spam : Karena Setiap Spam akan kami hapus