Belajar dengan membaca secara berurutan

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.

Argumen immutable
pemanggilx = 5di fungsix = 5x = 5(tidak berubah)x = 15(nilai baru)kirimx += 10
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

Tulis fungsi konversi pajak dan konfirmasikan bahwa mengubah argumen int tidak memengaruhi sisi luar.

① Definisikan def add_tax(price):, set price = int(price * 1.1), lalu cetak f"di dalam: {price}". (Tidak ada nilai kembalian kali ini.)

② Set base_price = 1000, panggil add_tax(base_price), lalu cetak f"di luar: {base_price}".

Keberhasilan berarti base_price di luar tidak berubah.

(Penjelasan muncul setelah ia berjalan dengan benar.)

Python Editor

Jalankan kode untuk melihat output

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.

Argumen mutable
pemanggilmy_list = [1, 2, 3]di fungsiitems = [1, 2, 3]my_list =[1, 2, 3, 100](juga berubah)items =[1, 2, 3, 100]kirim kotak yang samaitems.append(100)terpantul
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.

Rasakan langsung bagaimana data luar termodifikasi tanpa sengaja.

① Definisikan def add_item(cart, item):, jalankan cart.append(item), lalu cetak f"di dalam: {cart}". (Tidak ada return.)

② Siapkan my_cart = ["susu", "roti"], panggil add_item(my_cart, "telur"), lalu cetak f"di luar: {my_cart}".

Konfirmasikan bahwa "telur" juga berakhir di my_cart di luar (ini perbedaannya dengan kasus immutable di bagian sebelumnya).

Python Editor

Jalankan kode untuk melihat output

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.

Buat kotak baru dengan .copy() sebelum memodifikasi
items = cart.copy()items.append(x)cart aslitetap samatidak ada efek
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

Tulis ulang fungsi dari bagian sebelumnya menjadi versi aman yang tidak memodifikasi pemanggil.

① Definisikan def add_item_safely(cart, item):, salin input dengan items = cart.copy(), jalankan items.append(item), dan akhiri dengan return items.

② Siapkan my_cart = ["susu", "roti"] dan tangkap hasilnya dengan new_cart = add_item_safely(my_cart, "telur").

print() my_cart dan new_cart keduanya dan konfirmasikan bahwa my_cart asli tidak berubah sementara hanya new_cart yang menambahkan "telur".

Python Editor

Jalankan kode untuk melihat output
QUIZ

Cek Pemahaman

Jawab setiap pertanyaan satu per satu.

Soal 1Setelah menjalankan kode ini, berapa nilai x?
def f(value):
value += 10

x = 5
f(x)
print(x)

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?