Di balik Python Trivia #1 dan #2

Daripada blog ini kembali kosong, mari kita bahas Python Trivia babak pertama dan babak kedua yang saya keluarkan lebih dari satu tahun lalu! Mari kita mulai dari babak pertama.

Berikut ini cuplikan kode yang saya tulis:

class Kantong(object):
    def __init__(self, data=[]):
        self.data = data
    def add_data(self, angka):
        self.data.append(angka)
    def cetak(self):
        print 'Daftar angka:', self.data

Lalu mari kita pakai kelas di atas seperti berikut.

satu = Kantong()
satu.add_data(1)
satu.add_data(2)
satu.cetak()

Apa keluarannya?

Daftar angka: [1, 2]

Data yang kita miliki adalah [1, 2] yang berasal dari 2 pemanggilan add_data() dengan parameter 1 dan 2. Gak ada yg protes kan? 😀

Setelah itu, kita buah sebuah objek lain dari kelas yg sama. Lalu 3 buah data baru dimasukkan dan lalu dicetak.

dua = Kantong()
dua.add_data(3)
dua.add_data(4)
dua.add_data(5)
dua.cetak()

Hasilnya adalah.. jreng jreng jreng..

Daftar angka: [1, 2, 3, 4, 5]

Lho lho lho.. kok ada [1, 2] dan bukan cuma [3, 4, 5] padahal kita cuma memasukkan 3 angka di objek baru ini?

Mengapa begini mengapa begitu?

Kalau kita baca kelas Kandong sekali lagi, fungsi add_data akan memasukkan angka ke variabel self.data. Variabel ini diinisialisasi pada bagian constructor __init__() dan nilai awal yg dimasukkan adalah nilai yang ada dalam variabel data dari parameter si constructor.

Jika parameter pada constructor ini tidak diisi, maka secara default nilai data adalah sebuah list kosong []

...
def __init__(self, data=[]):
...

Objek satu dan dua yang dibuat dari kelas Kantong ini tidak menyertakan parameter saat objek dibuat. Alhasil, nilai [] tadi akan dijadikan nilai awal untuk self.data.

Pertanyaannya adalah kapan nilai [] dibuat? Ternyata nilai ini dibuat hanya satu kali pada saat kelas didefinisikan! Artinya, jika nilai tadi tidak diganti, semua objek yang berasal dari kelas Kantong akan memiliki variabel self.data yang sama! Walau tersebar di banyak objek, tapi variabel tersebut menunjuk ke sebuah list yang sama sehingga jika ada penambahan/pengurangan isi list tersebut, semua objek yang memegang list tersebut akan dapat melihatnya.

Lalu bagaimana?

Jika yang kita maksud dengan tidak memberikan parameter adalah sebuah list baru (dan kosong) akan dibuat, maka kelas di atas bisa diubah menjadi berikut.

class Kantong(object):
    def __init__(self, data=None):
        if data is None:
            self.data = []
        else:
            self.data = data
    ...

Dengan demikian, jika parameter tidak dimasukkan (yang artinya data akan bernilai None), variabel self.data akan diisi dengan sebuah list baru yang berbeda dengan list dari objek lain dari kelas yang sama.

Kesimpulannya, pada cara pertama, nilai self.data secara default akan diisi sebuah list yang dibuat pada saat kelas didefinisikan. Pemanggilan constructor (juga termasuk fungsi) akan menggunakan list yang sama dan efeknya adalah adanya penggunaan data bersama. Sedangkan pada contoh kelas ke dua, nilai self.data dibuat pada saat constructor/fungsi dijalankan sehingga pada setiap eksekusi, list baru dan berbeda akan dibuat dan efeknya tidak akan ada penggunaan data bersama.

Bagaimana dengan trivia babak kedua?

Kasus sama juga terjadi di sini.

a = [1] * 5

Kode di atas dapat dibaca seperti berikut. Buat sebuah list baru yang isinya adalah isi list sekarang yang diulang sebanyak 5 kali. Nilai dari a adalah seperti berikut.

[1, 1, 1, 1, 1]

Jika kita ubah salah satu elemennya..

a[3] = 200

Maka nilai si a akan menjadi..

[1, 1, 1, 200, 1]

Masih oke kan? 😀 Apa yang terjadi jika kita menggunakan dict dan bukan angka 1?

b = [{}] * 5

Nilai si b tentunya akan menjadi seperti berikut.

[{}, {}, {}, {}, {}]

Bagimana jika salah dict diubah isinya?

b[0]['a'] = 100

Baris kode di atas artinya ambil elemen nomor 0 dari b (yaitu sebuah dict), lalu kita set kunci 'a' supaya bernilai 100. Bagaimana jika kita cetak nilai si b?

[{'a': 100}, {'a': 100}, {'a': 100}, {'a': 100}, {'a': 100}]

Sesuatu yang (mungkin) tidak diharapkan terjadi lagi 😀 Lagi-lagi hal ini terjadi karena sebenarnya 5 buah dict yang ada di dalam b sebenarnya adalah dict yang sama namun dimasukkan sebanyak 5 kali di dalam list b.

Mudah2an jelas 😀

7 thoughts on “Di balik Python Trivia #1 dan #2”

  1. Halo Iang! Gabung ke PlanPin alias Planet Python Indonesia yuk 😉 Untuk tulisan dengan tag “python”, misalnya, akan muncul di PlanPin.

    Gimana?

Leave a Reply