Soal 1Setelah menjalankan kode ini, berapa nilai x?def f(value):
value += 10
x = 5
f(x)
print(x)
Argumen Fungsi dan Referensi Objek — Mutable Termodifikasi di Dalam Fungsi
Pahami perilaku argumen fungsi Python berdasarkan tipe mutable atau immutable agar terhindar dari bug referensi.
Saat kamu memanggil sebuah fungsi, perilakunya berubah tergantung apakah argumennya tipe mutable (list / dict / set) atau tipe immutable (int / str / tuple). Artikel ini menelusuri perbedaan itu dan pola dasar untuk menulis fungsi yang aman.
Argumen immutable — perubahan di dalam tidak bocor keluar
Integer, float, string, dan tuple adalah immutable (tidak bisa diubah di tempat). Terima salah satunya sebagai argumen dan tulis ulang dengan += 10 atau = some_other_value, dan variabel pemanggil tidak tersentuh.
Di balik layar, += 10 membuat nilai baru dan hanya mengikat ulang nama argumen di dalam — nama pemanggil masih menunjuk ke nilai aslinya.
def try_modify_number(value):
value += 10
print(f"di dalam: {value}")
x = 5
try_modify_number(x)
print(f"di luar: {x}")
# di dalam: 15
# di luar: 5 <- masih nilai asli
# Cerita yang sama untuk string dan tuple
def try_modify_text(text):
text = text + " world"
print(f"di dalam: {text}")
message = "hello"
try_modify_text(message)
print(f"di luar: {message}") # hello
Argumen mutable — perubahan di dalam bocor ke luar
Di sisi lain, saat kamu mengirim tipe mutable seperti list / dict / set dan memanggil sesuatu seperti .append() atau .update() untuk memodifikasi isinya di tempat, variabel pemanggil melihat perubahan yang sama.
Itu karena saat argumen dikirim, nama pemanggil dan nama argumen di dalam berbagi kotak yang sama. Itu mekanisme yang sama dengan y = x dari artikel mutable-vs-immutable sebelumnya — sekarang terjadi di batas pemanggilan.
def try_modify_list(items):
items.append(100)
print(f"di dalam: {items}")
my_list = [1, 2, 3]
try_modify_list(my_list)
print(f"di luar: {my_list}")
# di dalam: [1, 2, 3, 100]
# di luar: [1, 2, 3, 100] <- sisi luar juga berubah
# Sama dengan dict
def set_role(user, role):
user["role"] = role
admin = {"name": "Budi"}
set_role(admin, "admin")
print(admin) # {'name': 'Budi', 'role': 'admin'}
Saat mutasi di dalam bocor keluar, penyebabnya sulit dilacak
cart.append(...) terlihat sangat sengaja di barisnya sendiri. Tetapi karena append di dalam fungsi juga menjangkau my_list di luar, kamu bisa berakhir dengan gejala "list diam-diam bertambah" yang muncul di tempat yang sama sekali tidak berhubungan.
Memodifikasi hanya di dalam fungsi — lindungi argumen dengan .copy()
Saat kamu ingin membiarkan data pemanggil tetap dan hanya mengubah hal-hal di dalam fungsi, cukup letakkan .copy() di awal fungsi. Salin list, dict, atau set yang masuk ke kotak terpisah sebelum memodifikasinya, dan pemanggil tidak terpengaruh.
Kembalikan versi yang sudah dimodifikasi dengan return, dan pemanggil bisa memegang cart asli dan cart baru sekaligus. Setelah pola ini menjadi memori otot, kamu akan menulis fungsi aman bebas dari efek samping (tidak ada modifikasi pemanggil).
Alur lengkapnya: ① salin argumen dengan .copy() ke kotak terpisah → ② edit salinan → ③ kembalikan hasilnya. Hafalkan tiga langkah ini dan kamu bisa dengan aman mendesain fungsi apa pun yang menerima argumen mutable.
def add_item_safely(cart, item):
items = cart.copy() # salin ke kotak terpisah sebelum mengedit
items.append(item)
return items # kirim hasilnya kembali via return
my_cart = ["susu", "roti"]
new_cart = add_item_safely(my_cart, "telur")
print(my_cart) # ['susu', 'roti'] <- tidak tersentuh
print(new_cart) # ['susu', 'roti', 'telur'] <- list terpisah
Cek Pemahaman
Jawab setiap pertanyaan satu per satu.
Soal 2Setelah menjalankan kode ini, berapa nilai my_list?def g(items):
items.append(100)
my_list = [1, 2, 3]
g(my_list)
print(my_list)
Soal 3Saat kamu ingin mengembalikan list baru tanpa memodifikasi list pemanggil, apa hal pertama yang harus kamu lakukan?