Anda di sini

Pemrograman

Python 3 RLE BAB 6: Fungsi Fruitful

Aditya Suranata - 06 Januari 2016 13:01:18 0

6.1. Mengembalikan Nilai (Return)

Fungsi built-in yang telah kita gunakan, macam abs, pow, int, max, dan range, tentunya memberikan sebuah hasil. Memanggil masing-masing fungsi tersebut menghasilkan sebuah nilai, yang mana biasanya kita berikan ke variabel atau kita gunakan sebagai bagian dari sebuah ekspresi.

biggest = max(3, 7, 2, 5) 
x = abs(3 - 11) + 10

Sebelumnya, kita juga pernah menulis fungsi kita sendiri yang akan mengembalikan jumlah final dari perhitungan bunga berganda.

Pada bab ini, kita akan menulis banyak fungsi lagi yang mengembalikan nilai, yang mana kita akan menamai fungsi yang me-return/mengembalikan nilai tersebut dengan sebutan fungsi fruitful, agar namanya terdengar lebih baik. Contoh pertama fungsi fruitful adalah area, yang mengembalikan luas/area dari sebuah lingkaran yang radiusnya telah ditentukan:

def area(radius):
    b = 3.14159 * radius**2
    return b

Kita telah melihat pernyataan return sebelumnya, tapi pada fungsi fruitful pernyataan return memerlukan nilai return. Pernyataan ini berarti: nilai dulu ekspresi return, lalu return/kembalikan nilainya langsung sebagai hasil (buah) dari fungsi ini. Ekspresi yang disediakan bisa ditulis secara acak hingga rumit, jadi kita bisa menulis ulang fungsi ini seperti contoh berikut:

def area(radius):
    return 3.14159 * radius * radius

Tapi dilain sisi, variabel temporer seperti b pada contoh diatas akan membuat proses debugging jauh lebih mudah.

Terkadang akan sangat berguna ketika kita memiliki pernyataan return lebih dari satu, yaitu ada satu pada masing-masing cabang pengkondisian. Kita sudah pernah melihat fungsi built-in abs, sekarang kita melihat bagaimana kita menulis punya kita sendiri:

def absolute_value(x):
    if x < 0:
        return -x
    else:
        return x

Cara lain untuk menulis fungsi diatas adalah dengan menghilangkan else dan hanya mengikuti kondisi if dengan pernyataan return kedua.

def absolute_value(x):
    if x < 0:
        return -x
    return x

Coba renungkan mengenai versi ini dan yakinkan diri mu kalau keduanya bekerja sama persis. Pahami antara kedua versi ini.

Kode yang tampak setelah pernyataan return, atau ditempat lainnya tidak akan pernah dicapai oleh flow of execution, dinamakan dengan dead code, atau unreachable code.

Pada fungsi fruitful, adalah ide yang sangat bagus untuk memastikan kalau setiap jalur yang dilalui program selalu mencapai pernyataan return. Versi berikut dari absolute_value gagal mengikuti ide ini:

def bad_absolute_value(x):
    if x < 0:
        return -x
    elif x > 0:
        return x

Versi ini tidak benar karena jika yang terjadi adalah x sama dengan 0, maka tak ada satu pun dari kondisi yang ada bernilai benar, dan fungsinya akan berakhir tanpa mencapai pernyataan return. Pada kasus ini, nilai return-nya adalah nilai spesial yang dinamakan dengan None:

>>> print(bad_absolute_value(0))
None

Semua fungsi Python mengembalikan None ketika mereka tidak mengembalikan nilai lain.

Selain itu, juga dimungkinkan untuk menggunakan pernyataan return pada pertengahan perulangan for, yang dalam kasus tertentu dapat digunakan untuk mengontrol penghentian segera fungsi yang berjalan. Mari asumsikan kita ingin sebuah fungsi yang mencari kata pada daftar kata-kata.

def find_first_2_letter_word(xs):
    for wd in xs:
        if len(wd) == 2:
            return wd
    return ""
>>> find_first_2_letter_word(["This", "is", "a", "dead", "parrot"])
'is'
>>> find_first_2_letter_word(["I", "like", "cheese"])
''

Coba pahami kode ini dan yakinkan dirimu kalau pada contoh kasus return pertama, fungsinya me-return sementara masih memproses elemen kedua: yang artinya ia tidak mesti harus melintasi semua list untuk bisa me-return nilai yang sudah ia temukan.

6.2. Pengembangan Program

Pada titik ini, kamu harusnya sudah bisa membaca sebuah fungsi dan menjabarkan apa yang mereka lakukan. Juga, jika kamu sudah sering berlatih, kamu tentu sudah menulis beberapa fungsi-fungsi kecil. Seiring kamu menulis fungsi yang lebih besar, kamu mungkin mulai mengalami kesulitan-kesulitan, khususnya yang berhubungan dengan runtime dan semantic error.

Untuk mensiasati pengembangan program yang kerumitannya makin tinggi, kita akan memperkenalkan teknik yang bernama incremental development (pengembangan bertahap). Tujuan dari incremental development adalah untuk menghindari sesi debugging yang lama dengan hanya menambah dan menguji sejumlah kecil kode pada satu waktu.

Sebagai contoh, anggap kita ingin mencari jarak antara dua titik, dengan koordinat (x1, y1) dan (x2, y2). Dengan teori Pitagoras, jarak itu didapat dari:

Langkah pertama adalah mempertimbangkan seperti apa bentuk dari fungsi distance pada Python yang akan kita buat. Dengan kata lain, apa inputnya (parameter) dan apa outputnya (nilai return)?

Pada kasus ini, dua titik itu adalah inputnya, yang mana kita bisa merepresentasikannya menggunakan empat parameter. Nilai returnnya adalah distance (jaraknya), yang mana merupakan sebuah nilai floating-point.

Sejauh ini kita sudah bisa menulis outline dari fungsi yang menangkap pemikiran pemikiran kita yaitu:

def distance(x1, y1, x2, y2):
    return 0.0

Tentu nampak jelas, fungsi dengan versi ini tidak menghitung jarak; ia selalu me-return nol. Tapi secara sintaks itu masih benar, dan akan bisa jalan, yang artinya bahwa kita bisa mengujinya sebelum kita membuatnya lebih rumit.

Untuk mencoba fungsinya, kita memanggilnya dengan nilai sampel:

>>> distance(1, 2, 4, 6)
0.0

Kita memilih nilai tersebut agar jarak horisontalnya sama dengan 3 dan jarak vertikalnya sama dengan 4; dengan cara itu, hasilnya adalah 5 (sisi miring/hipotenuse dari segitiga 3-4-5). Ketika mencoba sebuah fungsi, tentu akan sangat berguna dan perlu untuk mengetahui hasilnya yang benar.

Pada titik ini kita bisa memastikan bahwa fungsinya benar secara syntaks, dan kita bisa mulai menambahkan baris-baris kode. Setelah setiap tahapan perubahan, kita menguji fungsinya lagi. Jika sebuah error terjadi pada titik manapun, kita tahu dimana ia tentunya berada -- ya, ia tentu berada pada baris terakhir yang kita tambahkan.

Langkah logis pertama pada perhitungannya adalah untuk menemukan selisih dari x2-x1 dan y2-y1. Kita akan merujuk ke nilai-nilai itu menggunakan nama variabel temporer dx dan dy.

def distance(x1, y1, x2, y2):
    dx = x2 - x1
    dy = y2 - y1
    return 0.0

Jika kita memanggil fungsi dengan argumennya seperti terlihat diatas, ketika flow of execution sampai pada pernyataan return, dx harusnya bernilai 3 dan dy bernilai 4. Kita bisa memeriksa kalau itu memang benar melalui PyScripter dengan menaruh kursor pada pernyataan return, dan menjalankan program agar menghentikan eksekusi ketika sampai pada kursor (menggunakan tombol F4). Lalu kita mengamati variabel dx dan dy dengan mengarahkan mouse pada mereka, untuk memastikan bahwa fungsinya mendapatkan parameter yang tepat dan melakukan perhitungan pertama dengan benar. Jika tidak, berarti hanya ada beberapa baris kode yang harus diperiksa lagi.

Selanjutnya kita menghitung jumlah kuadrat dari dx dan dy:

def distance(x1, y1, x2, y2):
    dx = x2 - x1
    dy = y2 - y1
    dsquared = dx*dx + dy*dy
    return 0.0

Dan lagi, kita bisa menjalakan program pada tahap ini dan memeriksa nilai dari dssquared (yang mana seharusnya bernilai 25).

Akhirnya, menggunakan eksponen fraksional 0.5 untuk mencari akar kuadrat, kita menghitung dan mengembalikan hasilnya:

def distance(x1, y1, x2, y2):
    dx = x2 - x1
    dy = y2 - y1
    result = dsquared**0.5
    return result

Jika bisa berjalan dengan benar, maka selesai sudah. Jika tidak, kamu mungkin perlu memeriksa nilai dari result sebelum pernyataan return.

Ketika kamu memulai, kamu bisa menambah hanya sebaris atau dua baris kode saja. Seiring meningkatnya pengalaman, kamu bisa merasakan dirimu menulis dan melakukan debugging bilahan konseptual yang lebih besar. Baik dengan cara, menguji kode selangkah demi selangkah dan memastikan kalau setiap langkah sesuai dengan harapan bisa menghemat banyak waktu mu untuk debugging. Seiring meningkatnya skil pemrograman mu, kamu akan merasakan dirimu bisa mengatur bilahan yang lebih besar dan besar lagi: ini sangat mirip dengan bagaimana kita belajar membaca mulai dari huruf, suku kata, kata-kata, ungkapan, kalimat, paragraf, dll., atau bagaimana kita belajar membilah musik -- dari not tunggal hingga chord, bar, frasa, dan seterusnya.

Aspek kunci dari prosesnya adalah:

  1. Mulai dengan kerangka program yang bisa jalan dulu dan buat perubahan kecil secara bertahap. Pada setiap titik, jika terjadi error, kamu akan tahu dengan pasti dimana ia berada.
  2. Gunakan variabel temporer untuk merujuk ke nilai saat ini jadi kamu bisa dengan mudah memeriksa dan menguji mereka.
  3. Setelah programnya bekerja, bersantai dulu tidak apa-apa, lalu duduk lagi, dan bermain-mainlah dengan pilihan-pilihan mu. (Ada penelitian menarik yang menghubungkan "bermain-main" dengan pemahaman yang lebih baik, pembelajaran yang lebih baik, lebih bisa menikmati, dan lebih punya pola pikir positif tentang apa yang bisa kamu capai -- jadi luangkan beberapa waktu untuk beremeh temeh!) Kamu juga bisa mengokohkan banyak pernyataan menjadi satu gabungan ekspresi yang lebih besar, atau mengganti nama variabel yang kamu gunakan, atau jika kamu bisa membuat fungsinya lebih pendek. Garis pedoman yang baik adalah bertujuan untuk membuat kodenya semudah mungkin untuk dibaca oleh orang lain.

Berikut adalah versi lain dari fungsi tersebut. Ia menggunakan fungsi akar pangkat dua yang berada di dalam modul math (kita akan belajar tentang modul beberapa saat lagi). Yang mana yang lebih kamu suka? Yang manakah yang terlihat lebih "mirip" dengan rumus Pitagoras yang kita mulai tadi?

import math

def distance(x1, y1, x2, y2):
    return math.sqrt( (x2-x1)**2 + (y2-y1)**2 )

>>> distance(1, 2, 4, 6)
5.0

6.3. Melakukan Debugging Dengan Fungsi print

Teknik lain untuk debugging yang juga powerful (sebuah alternatif dari single-stepping dan pemeriksaan variabel program), adalah menambahkan fungsi print ekstra pada tempat yang benar-benar diperlukan pada kode mu. Kemudian, dengan mengamati output dari program, kamu bisa memeriksa apakah algoritmanya melakukan apa yang kamu harapkan. Dengan catatan, harap pahami dengan baik hal-hal berikut:

  • Kamu harus punya solusi yang jelas mengenai masalah, dan harus tahu apa yang mestinya terjadi sebelum kamu melakukan debugging pada program. Lakukan pemecahan masalah pada selembar kertas (sebaiknya gunakan flowchart untuk mencatat langkah-langkah yang kamu ambil) sebelum kamu memfokuskan diri dengan menulis kode. Ingat kalau menulis program saja tidak akan memecahkan masalahnya -- itu sederhananya hanya mengotomatiskan langkah-langkah manual yang mesti kamu ambil. Jadi pertama pastikan kamu punya pulpen - dan - kertas yang berisi solusi panduan yang benar-benar bekerja dan bisa diandalkan. Kemudian barulah pemrograman hanya tentang membuat langkah-langkah manual tersebut terjadi secara otomatis.
  • Jangan menulis fungsi-fungsi yang penuh bualan (chatterbox function). Sebuah fungsi pembual adalah fungsi fruitful yang: melakukan hal selain tugas utamanya, juga menanyakan pengguna berbagai input, atau mencetak output yang tidak berguna, dan ketika semuanya akan menjadi jauh lebih berguna jika dia diam dan melakukan tugasnya tanpa berisik.

Sebagai contoh, kita sudah melihat fungsi built-in seperti range, max dan abs. Tak ada satupun dari fungsi tersebut menjadi block bangunan yang berguna untuk program lain jika mereka meminta pengguna untuk memasukan sebuah input, atau mencetak hasil mereka sementara mereka melakukan tugasnya. Bisa kalian bayangkan bagaimana ruwetnya program kita jika fungsi-fungsi itu melakukan hal itu.

Jadi tips yang baik adalah menghindari memanggil fungsi print dan fungsi input didalam fungsi fruitful, kecuali tujuan utama dari fungsi mu adalah untuk melakukan input dan output. Satu pengecualian pada aturan ini adalah kita bisa sementara waktu menghamburkan beberapa pemanggilan pada fungsi print kedalam kode kita untuk membantu melakukan debug dan memahami apa yang terjadi ketika kode dijalankan, tapi setelah selesai dan programnya sudah berjalan dengan baik tentu semuanya harus dihilangkan.

6.4. Komposisi

Seperti apa yang kamu harapkan saat ini, kamu bisa memanggil satu fungsi di dalam fungsi lainnya. Kemampuan ini dinamakan dengan komposisi.

Sebagai salah satu contoh, kita akan menulis sebuah fungsi yang mengambil dua titik, pusat dari lingkaran dan satu lagi tepi lingkaran, dan menghitung luas dari lingkaran.

Asumsikan kalau titik pusat disimpan pada variabel xc dan yc, dan titik tepinya pada xp dan yp. Langkah pertama adalah menemukan radius dari lingkaran, yang mana merupakan jarak antara dua titik tersebut. Untungnya, kita telah menulis fungsi, distance, yang bisa melakukan hal itu, jadi sekarang semua yang harus kita lakukan adalah cukup menggunakannya:

radius = distance(xc, yc, xp, yp)

Langkah kedua adalah mencari luas dari lingkaran dengan radius tersebut dan mengembalikannya. Sekali lagi kita akan menggunakan fungsi kita sebelumnya:

result = area(radius)
return result

Membalutnya kedalam fungsi, hingga menjadi:

def area2(xc, yc, xp, yp):
    radius = distance(xc, yc, xp, yp)
    result = area(radius)
    return result

Kita menamakan fungsi ini area2 untuk membedakannya dari fungsi area yang didefinisikan sebelumnya.

Variabel temporer radius dan result berguna untuk pengembangan, debugging, dan single-stepping pada kode untuk mengamati apa yang terjadi, tapi ketika programnya bekerja dengan baik, kita bisa membuatnya menjadi lebih ringkas dengan mengkomposisi pemanggilan fungsinya:

def area2(xc, yc, xp, yp):
    return area(distance(xc, yc, xp, yp))

6.5. Fungsi Boolean

Fungsi bisa mengembalikan nilai Boolean, yang mana sering berguna untuk menyembunyikan tes rumit di dalam fungsi. Sebagai contoh:

def is_divisible(x,y):
    """ Tes jika x bisa dibagi dengan y """
    if x % y == 0:
        return True
    else:
        return False

Sangat umum untuk memberikan nama fungsi Boolean yang terdengar seperti pertanyaan yang jawabannya iya/tidak. is_divisible mengembalikan baik True atau False untuk menandakan apakah x bisa atau tidak bisa dibagi dengan y.

Kita bisa membuat fungsinya lebih ringkas dengan memanfaatkan keuntungan dari fakta bahwa konfisi dari pernyataan if sendiri merupakan ekspresi Boolean. Kita bisa me-returnnya langsung, tanpa perlu pernyataan if lagi:

def is_divisable(x, y):
    return x % y == 0

Berikut output ketka fungsi baru ini dijalankan:

>>> is_divisible(6, 4)
False
>>> is_divisible(6, 3)
True

Fungsi boolean sering kali digunakan pada pernyataan kondisional:

if is_divisable(x, y):
    ... # Lakukan sesuatu ...
else:
    ... # Lakukan sesuatu lainnya ...

Mungkin lebih menggiurkan kalau ditulis menjadi:

if is_divisible(x, y) == True:

tapi perbandingan ekstranya ( == True ) tidak perlu ditulis agar tidak panjang.

6.6. Style Dalam Pemrograman

Aspek kejelasan dan bisa dibaca sangat penting untuk programmer, karena pada praktiknya program lebih sering dibaca dan dimodifikasi lalu baru ditulis. Tapi, seperti aturan umumnya, kita terkadang melanggarnya. Maka dari itu, kebanyakan dari contoh kode pada buku ini akan konsisten dengan Python Enhancement Proposal 8 (PEP 8), yang merupakan sebuah panduan style yang dikembangkan oleh komunitas Ptyhon.

Kita akan berbicara lebih banyak lagi mengenai style seiring bertambah rumitnya program kita, tapi sebagai awal beberapa poin ini akan bisa membantu untuk memahami poinnya:

  • gunakan 4 spasi (jangan tab) untuk indentasi
  • batasi panjang satu baris menjadi 78 karakter
  • ketika menamai indentifier, gunakan CamelCase untuk kelas (kita akan mempelajari tentang kelas secepatnya) dan lower_case_with_underscore untuk fungsi dan variabel.
  • tempatkan import pada bagian atas file
  • jaga definisi fungsi tetap bersama, jangan meletakan definisi fungsi secara acak
  • gunakan docstring untuk mendokumentasikan fungsi
  • gunakan dua baris kosong untuk memisahkan definisi fungsi satu sama lain
  • jaga pernyataan tingkat atas, termasuk pemanggilan fungsi, bersama-sama pada bagian bawah dari program

6.7. Unit Testing

Pada umumnya merupakan sebuah praktik yang baik dalam pengembangan perangkat lunak untuk menyertakan unit testing (pengujian unit) terotomatisasi dari kode sumber. Unit testing menyediakan cara yang secara otomatis memastikan kalau setiap potongan kode, seperti fungsi, bisa berjalan dengan baik. Ini memungkinkan kita untuk merubah implementasi dari fungsi dilain waktu dan dengan cepat menguji apakah ia masih melakukan apa yang seharusnya dilakukan.

Beberapa tahun belakangan ini organisasi-organisasi memiliki pandangan bahwa aset berharga mereka adalah kode program dan dokumentasi. Organisasi tersebut sekarang akan menghabiskan porsi besar dari anggaran belanja perangkat lunak mereka pada kerajinan (dan pelestarian) pengujian aset mereka itu.

Unit testing juga memaksa programmer untuk berpikir mengenai kasus yang berbeda yang perlu ditangani oleh fungsi. Kamu juga hanya perlu menulis pengujiannya sekali pada script, ketimbang harus memasukan data pengujian yang sama lagi dan lagi seiring kamu mengembangkan kode mu.

Kode ekstra pada program mu yang tujuannya membuat debugging atau pengujian menjadi lebih mudah dinamakan sebagai scaffolding.

Sekumpulan pengujian untuk beberapa kode dinamakan sebagai test suite.

Terdapat berbagai cara untuk melakukan unit testing di Python -- tapi pada tahap ini kita akan mengabaikan apa yang komunitas Python biasa gunakan, dan kita akan mulai dengan dua fungsi yang akan kita tulis sendiri. Kita akan menggunakan mereka untuk menulit unit test kita.

Mari mulai dengan fungsi absolute_value yang kita tulis sebelumnya pada bab ini. Ingat bahwa kita menulis beberapa versi berbeda, yang mana yang terakhir ditulis salah, dan punya bug. Bisakah pengujiannya menemukan bug ini?

Pertama kita merencanakan pengujian kita. Kita perlu mengetahui jika fungsinya me-return nilai yang benar ketika argumennya negatif, atau ketika argumennya positif, atau , ketika argumennya nol. Ketika kamu merencanakan pengujian, kamu akan selalu perlu untuk memikirkan dengan hati-hati mengenai kasus "tepi" -- disini, sebuah argumen dari 0 ke absolute_value berada pada tepi dari perubahan prilaku fungsi, dan seperti yang kita lihat pada awal bab ini, merupakan titik yang paling mudah untuk programmer membuat sebuah kesalahan! Jadi merupakan kasus yang baik untuk menyertakannya pada test suite kita.

Kita akan menulis sebuah fungsi helper untuk mengecek hasil dari satu pengujian. Ia akan mengambil sebuah argumen boolean dan akan mencetak pesan apakah pengujiannya berhasil atau gagal. Baris pertama dari body (setelah docstring fungsi) secara ajaib menentukan nomer baris pada skrip dimana pemanggilan dilakukan. Ini memungkinkan kita untuk mencetak nomer baris dari pengujian, yang mana akan membantu ketika kita ingin mengidentifikasi pengujian yang berhasil dan gagal.

import sys

def test(did_pass):
    """ Cetak hasil dari pengujian. """
    linenum = sys._getframe(1).f_lineno #Dapatkan nomer baris dari pemanggil
    if did_pass:
        msg = "Pengujian pada baris {0} berhasil.".format(linenum)
    else:
        msg = ("Pengujian pada baris {0} GAGAL.".format(linenum))
    print(msg)

Juga terdapat pembentukan string yang sedikit rumit menggunakan metode format, kita akan abaikan ini sementara waktu, dan kita bahas dengan detail pada bab berikutnya. Tapi dengan ditulisnya fungsi ini, kita bisa melanjutkan untuk membangun test suite kita:

def test_suite():
    """ Menjalankan suite tes untuk kode pada modul ini (file ini).
    """
    test(absolute_value(17) == 17)
    test(absolute_value(-17) == 17)
    test(absolute_value(0) == 0)
    test(absolute_value(3.14) == 3.14)
    test(absolute_value(-3.14) == 3.14)

test_suite()    # Disini merupakan pemanggilan untuk menjalankan pengujiannya

Disini kamu akan melihat kalau kita telah membangun lima pengujian pada test suite kita. Kita bisa menjalankan ini pada versi pertama atau kedua (versi yang benar) dari absolute_value, dan kita akan mendapatkan output seperti:

Pengujian pada baris 25 berhasil.
Pengujian pada baris 26 berhasil.
Pengujian pada baris 27 berhasil.
Pengujian pada baris 28 berhasil.
Pengujian pada baris 29 berhasil.

Tapi mari katakan kamu merubah fungsinya menjadi versi yang salah seperti ini:

def absolute_value(n):   # Versi buggy
    """ Hitung nilai absolut dari n """
    if n < 0:
        return 1
    elif n > 0:
        return n

Bisakan kamu menemukan dua kesalahan pada kode tersebut? Test suite kita bisa menemukannya! Kita mendapatkan:

Pengujian pada baris 25 berhasil.
Pengujian pada baris 26 GAGAL.
Pengujian pada baris 27 GAGAL.
Pengujian pada baris 28 berhasil.
Pengujian pada baris 29 GAGAL.

Terdapat tiga contoh dari test yang gagal.

Terdapat pernyataan Python built-in bernama assert yang melakukan hal yang hampir sama seperti fungsi test kita (tapi kalau menggunakan assert maka programnya akan berhenti pada pengujian pertama yang gagal). Kamu mungkin ingin membaca tentangnya, dan menggunakannya ketimbang menggunakan fungsi pengujian yang kita buat tadi.

6.8. Glosarium

fungsi Boolean

Fungsi yang mengembalikan nilai Boolean. Nilai yang ada pada tipe bool hanyalah True dan False.

chatterbox function (fungsi pembual)

Sebuah fungsi yang berinteraksi dengan pengguna (menggunakan input atau print) ketika mestinya tidak ia lakukan. Fungsi pendiam yang hanya mengkonversi argumen inputnya menjadi output merupakan satu yang paling berguna, kebalikan dari fungsi pembual.

composition (of function) - komposisi fungsi

Memanggil satu fungsi dari dalam body fungsi lainnya, atau menggunakan nilai return dari satu fungsi sebagai sebuah argumen untuk pemanggilan fungsi lainnya.

dead code

Bagian dari program yang tidak mungkin bisa dieksekusi, sering kali karena terletak setelah pernyataan return.

fruitful function

Fungsi yang menghasilkan nilai return ketimbang None.

incremental development (pengembangan bertahap)

Rencana pengembangan program yang bertujuan untuk menyederhanakan proses debugging dengan menambahkan dan menguji hanya sejumlah kecil dari kode pada satu waktu.

None

Nilai spesial pada Python. Salah satu penggunaannya di Python adalah ia dikembalikan (di-return) oleh fungsi yang tidak mengeksekusi pernyataan return dengan argumen return.

return value

Nilai yang diberikan sebagai hasil dari sebuah pemanggilan fungsi.

scaffolding

Kode yang digunakan selama pengembangan program untuk menuntun kita pada tahap pengembangan dan debugging. Kode unit test yang kita tambahkan pada bab ini adalah contoh dari scaffolding.

temporary variable (variabel temporer)

Variabel yang digunakan untuk menyimpan nilai saat ini pada perhitungan rumit untuk keperluan pengembangan dan debugging.

test suite

Sekumpulan pengujian-pengujian dari beberapa kode yang telah kamu tulis.

unit testing

Prosedur otomatis yang digunakan untuk memastikan bahwa unit individu dari kode bekerja sebagai mana mestinya. Memiliki test suite sangat berguna ketika seseorang memodifikasi atau mengembangkan kodenya: ia akan menyediakan jaring pengaman agar kita tidak mundur lagi karena adanya bug baru yang tak sengaja kita masukan pada kode yang sebelumnya sudah bekerja dengan baik. Istilah regression testing (pengujian kemunduran) sering kali digunakan untuk mengungkapkan ide ini kalau kita tidak ingin untuk melangkah mundur!

6.9. Latihan

Semua latihan berikut harus ditambahkan ke satu file. Pada file tersebut, kamu mesti juga menambah fungsi scaffolding test dan test_suite seperti terlihat diatas, lalu kemudian, seiring kamu mulai mengerjakan latihannya, tambahkan pengujian baru ke test suite mu. (copy paste kodenya ke Python editor.)

Setelah menyelesaikan setiap latihan, pastikan kalau semua pengujian berhasil.

1. Empat arah mata angin bisa disingkat menjadi string satu huruf dalam bahasa Inggris seperti "N", "E", "S", dan "W". Tulis fungsi turn_clockwise yang mengambil satu dari arah mata angin tersebut sebagai parameternya, dan kembalikan arah mata angin selanjutnya kearah yang berlawanan. Berikut adalah beberapa pengujian yang mesti berhasil:

test(turn_clockwise("N") == "E")
test(turn_clockwise("W") == "N")

Kamu mungkin bertannya "Bagaimana jika argumen fungsinya merupakan nilai selain keempat nilai diatas?" Untuk semua kasus lainnya, fungsinya semestinya me-return nilai None:

test(turn_clockwise(42) == None)
test(turn_clockwise("rubbish") == None)

2. Tulis sebuah fungsi day_name yang mengkonversi sebuah bilangan integer 0 hingga 6 menjadi nama-nama hari. Asumsikan kalau 9 adalah "Sunday". Sekali lagi, return None jika argumen fungsinya tidak valid. Berikut merupakan beberapa pengujian yang harus berhasil dijalankan:

test(day_name(3) == "Wednesday")
test(day_name(6) == "Saturday")
test(day_name(42) == None)

3. Tulis kebalikan dari fungsi day_num yang mana sekarang menerima nama, dan me-return nomer:

test(day_num("Friday") == 5)
test(day_num("Sunday") == 0)
test(day_num(day_name(3)) == 3)
test(day_name(day_num("Thursday")) == "Thursday")

Sekali lagi, jika fungsi ini diberikan argumen yang tidak valid, ia harus me-return None:

test(day_num("Halloween") == None)

4. Tulis fungsi yang membantu menjawab pertanyaan seperti '"Hari ini adalah Wednesday. Saya pergi berlibur 19 hari dari sekarang. Hari apakah itu?"' Jadi fungsinya harus mengambil nama hari dan argumen delta -- jumlah dari hari untuk ditambahkan -- dan harus me-return nama hari yang dimaksud:

test(day_add("Monday", 4) ==  "Friday")
test(day_add("Tuesday", 0) == "Tuesday")
test(day_add("Tuesday", 14) == "Tuesday")
test(day_add("Sunday", 100) == "Tuesday")

Petunjuk: gunakan dua fungsi pertama yang ditulis diatas untuk membantu mu menulis yang ini.

5. Bisakah fungsi day_add mu bekerja dengan delta negatif? Sebagai contoh, -1 harusnya kemarin, atau -7 akan menjadi seminggu yang lalu:

test(day_add("Sunday", -1) == "Saturday")
test(day_add("Sunday", -7) == "Sunday")
test(day_add("Tuesday", -100) == "Sunday")

Jika fungsi mu sudah bekerja, jelaskan kenapa. Jika belum, buat biar bisa bekerja.

Petunjuk: Bermainlah dengan beberapa kasus menggunakan fungsi modulus % (yang dijelaskan pada awal bab sebelumnya). Khususnya, cari tahu apa yang terjadi pada x % 7 ketika x adalah negatif.

6. Tulis fungsi day_in_month yang mengambil nama-nama bulan, dan mereturn tanggal dari hari. Abaikan tahun kabisat:

test(days_in_month("February") == 28)
test(days_in_month("December") == 31)

Jika fungsinya diberikan argumen yang tidak valid, ia mesti mereturn None.

7. Tulis fungsi to_secs yang mengkonversi jam, menit dan detik dari sejumlah bilangan dalam detik. Berikut adalah beberapa pengujian yang mesti berhasil dilewati:

test(to_secs(2, 30, 10) == 9010)
test(to_secs(2, 0, 0) == 7200)
test(to_secs(0, 2, 0) == 120)
test(to_secs(0, 0, 42) == 42)
test(to_secs(0, -10, 10) == -590)

8. Kembangkan to_sec sehingga ia bisa mengatasi nilai riil sebagai input. Ia mesti selalu me-return sebuah bilangan integer dari detik (dibulatkan menjadi nol):

test(to_secs(2.5, 0, 10.71) == 9010)
test(to_secs(2.433,0,0) == 8758)

9. Tulis tiga fungsi yang merupakan "kebalikan" dari to_secs:

  1. hours_in mengembalikan semua bilangan integer dalam jam yang direpresentasikan oleh jumlah total dari detik.
  2. minutes_in mengembalikan semua bilangan integer dalam menit tersisa dalam jumlah total dari detik, setelah jamnya dikeluarkan.
  3. seconds_in mengembalikan detik tersisa direpresentasikan oleh jumlah total dari detik.

Kamu bisa mengasumsikan kalau jumlah total dari detik yang lewat pada fungsi tersebut merupakan sebuah integer. Berikut adalah beberapa kasus pengujiannya:

test(hours_in(9010) == 2)
test(minutes_in(9010) == 30)
test(seconds_in(9010) == 10)
Tidak akan selalu terlihat jelas apa yang diinginkan
Pada kasus ketiga diatas, hal yang diperlukan terlihat cukup ambigu dan rancu. Tapi yang terakhir menjelaskan apa yang kita benar-benar perlu lakukan.

Unit test sering memiliki kelebihan sekunder ini, yaitu adanya kejelasan spesifikasi. Jika kamu menulis test suite mu sendiri, pertimbangkan agar menjadi bagian dari proses pemecahan masalah seperti kamu menanyakan pertanyaan tentang apa yang kamu benar-benar harapkan terjadi, dan apakah kamu telah mempertimbangkan semua kasus yang mungkin terjadi.

Karena buku kita berjudul Bagaimana Berpikir Layaknya .... kamu mungkin menikmati membaca setidaknya satu referensi tentang berpikir, dan tentang ide menyenangkan seperti fluid intelligence, kunci bahan-bahan dalam pemecehan masalah. Lihat, sebagai contoh, http://psychology.about.com/od/cognitivepsychology/a/fluid-crystal.htm. Belajar Ilmu Komputer memerlukan campuran yang baik dari kecerdasan yang encer dan terkristal.

10. Yang mana dari pengujian berikut yang gagal? Coba jelaskan.

test(3 % 4 == 0)
test(3 % 4 == 3)
test(3 / 4 == 0)
test(3 // 4 == 0)
test(3+4  *  2 == 14)
test(4-2+2 == 0)
test(len("hello, world!") == 13)

11. Tulis fungsi compare yang mengembalikan 1 jika a > b, 0 jika a == b, dan -1 jika a < b

test(compare(5, 4) == 1)
test(compare(7, 7) == 0)
test(compare(2, 3) == -1)
test(compare(42, 1) == 1)

12. Tulis fungsi bernama hypotenuse yang mengembalikan panjang dari hypotenuse dari segitiga yang benar sesuai dengan panjang dari dua kakinya sebagai parameter:

test(hypotenuse(3, 4) == 5.0)
test(hypotenuse(12, 5) == 13.0)
test(hypotenuse(24, 7) == 25.0)
test(hypotenuse(9, 12) == 15.0)

13. Tulis fungsi slope(x1, y1, x2, y2) yang mengembalikan lereng dari garis melalui titik (x1, y1) dan (x2, y2). Pastikan implementasin dari slope mu bisa melewat pengujian berikut:

test(slope(5, 3, 4, 2) == 1.0)
test(slope(1, 2, 3, 2) == 0.0)
test(slope(1, 2, 3, 3) == 0.5)
test(slope(2, 4, 1, 2) == 2.0)

Kemudian lakukan pemanggilan ke slope dari fungsi baru bernama intercept(x1, y1, x2, y2) yang mengembalikan pemotongan dari garis y melalui titik (x1, y1) dan (x2, y2)

test(intercept(1, 6, 3, 12) == 3.0)
test(intercept(6, 1, 1, 6) == 7.0)
test(intercept(4, 6, 12, 8) == 5.0)

14. Tulis fungsi bernama is_even(n) yang mengambil sebuah integer sebagai argumen dan mengembalikan True jika argumennya merupakan bilangan genap dan False jika ganjil.

Tambahkan pengujian mu sendiri untuk menguji test suitenya.

15. Sekarang tulis fungsi is_odd(n) yang mengembalikan True ketika n adalah ganjil dan False jika sebaliknya. Sertakan juga unit test untuk fungsi ini.

Terakhir, modifikasi agar menggunakan call ke is_even untuk menentukan jika argumennya adalah sebuah integer ganji, dan memastikan semua pengujiannya berhasil.

16. Tulis fungsi is_factor(f, n) yang bisa melewati pengujian berikut:

test(is_factor(3, 12))
test(not is_factor(5, 12))
test(is_factor(7, 14))
test(not is_factor(7, 15))
test(is_factor(1, 15))
test(is_factor(15, 15))
test(not is_factor(25, 15))

Kegunaan penting dari unit test adalah bisa juga digunakan sebagai "spesifikasi" yang tidak ambigu dari apa yang diharapkan. Kasus pengujian tersebut menjawab pertanyaan Apakah kita memperlakukan 1 dan 15 sebagai faktor dari 15?

17. Tulis is_multiple untuk melewati unit test berikut:

test(is_multiple(12, 3))
test(is_multiple(12, 4))
test(not is_multiple(12, 5))
test(is_multiple(12, 6))
test(not is_multiple(12, 7))

Bisakah kamu menemukan cara untuk menggunakan is_factor dalam definisi dari is_multiple yang kamu buat?

18. Tulis fungsi f2c(t) yang didesain agar mengembalikan nilai integer dari derajat Celcius yang paling mendekati dengan temperatur dalam Fahrenheit. (petunjuk: kamu akan perlu mempergunakan fungsi built-in, round. Coba cetak round.__doc_ di Python shell atau lihat menu help mengenai fungsi round, dan coba bereksperimen hingga kamu nyaman dan paham bagaimana cara kerja dan menggunakannya.)

test(f2c(212) == 100)     # Titik didih air
test(f2c(32) == 0)        # Titik beku air
test(f2c(-40) == -40)     # Wow, what an interesting case!
test(f2c(36) == 2)
test(f2c(37) == 3)
test(f2c(38) == 3)
test(f2c(39) == 4)

19. Sekarang lakukan kebalikannya: tulis fungsi c2f yang mengkonversi Celcius ke Fahrenheit:

test(c2f(0) == 32)
test(c2f(100) == 212)
test(c2f(-40) == -40)
test(c2f(12) == 54)
test(c2f(18) == 64)
test(c2f(-48) == -54)

2.643
Daftar Artikel Terkait
Image

Aditya Suranata

Aditya suka menulis, bukan hanya sekedar hobi, menulis menjadi medianya untuk mencurahkan pikiran dan perasaan. Di TutorKeren.com kebanyakan menyumbang tulisan sesuai dengan minat dan keahliannya yaitu pada kategori pemrograman dan elektronika. Selain itu juga gemar menulis mengenai hal-hal umum, seperti ilmu alam, sosial dan beberapa pengalamannya yang mungkin bisa berguna untuk orang lain.

Artikel Menarik Lainnya
Mari Gabung

Halo Emo 51 , Ada yang ingin disampaikan? Jangan sungkan untuk gabung diskusi ini. Silahkan Login dulu atau Daftar baru.