Python & AI Tutorials Logo
Pemrograman Python

20. Parameter dan Argumen Fungsi

Di Bab 19, kita belajar cara mendefinisikan dan memanggil fungsi(function) dengan parameter dasar. Sekarang kita akan mengeksplorasi sistem parameter dan argumen Python yang fleksibel secara mendalam. Memahami mekanisme ini memungkinkan kamu menulis fungsi yang sekaligus kuat dan mudah digunakan.

20.1) Argumen Positional dan Keyword

Saat kamu memanggil sebuah fungsi, kamu bisa mengoper argumen dengan dua cara mendasar: berdasarkan posisi atau berdasarkan nama (keyword).

20.1.1) Argumen Positional

Argumen positional dicocokkan dengan parameter berdasarkan urutannya. Argumen pertama masuk ke parameter pertama, argumen kedua ke parameter kedua, dan seterusnya.

python
def calculate_discount(price, discount_percent):
    """Calculate the final price after applying a discount."""
    discount_amount = price * (discount_percent / 100)
    final_price = price - discount_amount
    return final_price
 
# Mengoper argumen berdasarkan posisi
result = calculate_discount(100, 20)
print(result)

Output:

80.0

Dalam contoh ini, 100 ditetapkan ke price dan 20 ke discount_percent murni berdasarkan posisinya dalam pemanggilan fungsi.

Urutan sangat krusial pada argumen positional:

python
# Contoh: Kita ingin menghitung item seharga $100 dengan diskon 20%
 
# Urutan benar: price dulu, lalu discount
print(calculate_discount(100, 20))
 
# Urutan salah: discount dulu, lalu price
print(calculate_discount(20, 100))

Output:

80.0
-16.0

Saat kamu menukar argumen, Python tidak tahu kamu membuat kesalahan—Python hanya menetapkannya sesuai urutan. Ini menghasilkan nilai yang secara matematis valid tetapi secara logika salah (harga negatif!).

20.1.2) Argumen Keyword

Argumen keyword secara eksplisit menyebutkan parameter mana yang menerima nilai tertentu dengan menggunakan nama parameter diikuti tanda sama dengan dan nilainya. Ini membuat kode kamu lebih mudah dibaca dan melindungi dari kesalahan urutan.

python
def create_user_profile(username, email, age):
    """Create a user profile with the given information."""
    profile = f"User: {username}\nEmail: {email}\nAge: {age}"
    return profile
 
# Menggunakan argumen keyword
profile = create_user_profile(username="alice_smith", email="alice@example.com", age=28)
print(profile)

Output:

User: alice_smith
Email: alice@example.com
Age: 28

Dengan argumen keyword, urutan tidak berpengaruh:

python
# Hasil sama, urutan berbeda
profile1 = create_user_profile(username="bob", email="bob@example.com", age=35)
profile2 = create_user_profile(age=35, username="bob", email="bob@example.com")
profile3 = create_user_profile(email="bob@example.com", age=35, username="bob")
 
# Ketiganya menghasilkan output yang identik
print(profile1 == profile2 == profile3)

Output:

True

Fleksibilitas ini sangat berharga terutama saat sebuah fungsi punya banyak parameter, sehingga mudah melihat nilai mana yang sesuai dengan parameter mana.

20.1.3) Mencampur Argumen Positional dan Keyword

Kamu bisa menggabungkan kedua gaya ini dalam satu pemanggilan fungsi, tetapi ada aturan penting: argumen positional harus muncul sebelum argumen keyword.

python
def format_address(street, city, state, zip_code):
    """Format a mailing address."""
    return f"{street}\n{city}, {state} {zip_code}"
 
# Valid: argumen positional dulu, lalu argumen keyword
address = format_address("123 Main St", "Springfield", state="IL", zip_code="62701")
print(address)

Output:

123 Main St
Springfield, IL 62701

Di sini, "123 Main St" dan "Springfield" adalah positional (ditetapkan ke street dan city), sementara state dan zip_code ditentukan berdasarkan nama.

Mencoba menaruh argumen positional setelah argumen keyword akan menyebabkan error:

python
# Tidak valid: argumen positional setelah argumen keyword
# address = format_address(street="123 Main St", "Springfield", state="IL", zip_code="62701")
# SyntaxError: positional argument follows keyword argument

Python menegakkan aturan ini karena setelah kamu mulai menggunakan argumen keyword, menjadi ambigu parameter positional mana yang harus diisi oleh argumen tanpa nama berikutnya.

20.1.4) Kapan Menggunakan Masing-Masing Gaya

Gunakan argumen positional saat:

  • Fungsi memiliki sedikit parameter (biasanya 1-3)
  • Urutan parameter jelas dan intuitif
  • Fungsi sering dipakai dan urutannya sudah umum diketahui
python
# Jelas dan ringkas
print(len("hello"))
result = max(10, 20, 5)

Gunakan argumen keyword saat:

  • Fungsi memiliki banyak parameter
  • Makna parameter tidak langsung jelas
  • Kamu ingin melewati beberapa parameter yang punya nilai default (dibahas berikutnya)
  • Kamu ingin membuat kode kamu self-documenting
python
# Jelas dan eksplisit
user = create_user_profile(username="charlie", email="charlie@example.com", age=42)

20.2) Nilai Default Parameter

Fungsi dapat menentukan nilai default untuk parameter. Saat pemanggil tidak memberikan argumen untuk parameter yang punya default, Python menggunakan nilai default tersebut.

20.2.1) Mendefinisikan Parameter dengan Default

Nilai default ditentukan dalam definisi fungsi menggunakan operator penugasan:

python
def greet_user(name, greeting="Hello"):
    """Greet a user with a customizable greeting."""
    return f"{greeting}, {name}!"
 
# Menggunakan greeting default
print(greet_user("Alice"))
 
# Memberikan greeting kustom
print(greet_user("Bob", "Good morning"))
print(greet_user("Carol", greeting="Hi"))

Output:

Hello, Alice!
Good morning, Bob!
Hi, Carol!

Parameter greeting memiliki nilai default "Hello". Saat kamu memanggil greet_user("Alice"), Python memakai default ini. Saat kamu memberikan argumen kedua, nilainya menimpa default.

20.2.2) Parameter dengan Default Harus Setelah Parameter Wajib

Python mewajibkan parameter yang punya nilai default muncul setelah semua parameter tanpa default. Aturan ini mencegah ambiguitas tentang argumen mana yang sesuai dengan parameter mana.

python
# Benar: parameter wajib dulu, lalu default
def create_product(name, price, category="General", in_stock=True):
    """Create a product record."""
    return {
        "name": name,
        "price": price,
        "category": category,
        "in_stock": in_stock
    }
 
product = create_product("Laptop", 999.99)
print(product)

Output:

{'name': 'Laptop', 'price': 999.99, 'category': 'General', 'in_stock': True}

Mencoba menaruh parameter wajib setelah parameter dengan default akan menyebabkan syntax error:

python
# Tidak valid: parameter wajib setelah parameter default
# def invalid_function(name="Unknown", age):
#     return f"{name} is {age} years old"
# SyntaxError: non-default argument follows default argument

Ini masuk akal: jika name punya default tetapi age tidak, bagaimana Python tahu apakah invalid_function(25) berarti name=25 dengan age tidak diisi, atau age=25 dengan name memakai default? Aturan ini menghilangkan ambiguitas tersebut.

20.2.3) Kegunaan Praktis Parameter Default

Parameter default sangat bagus untuk fungsi di mana argumen tertentu jarang berubah:

python
def calculate_shipping(weight, distance, express=False):
    """Calculate shipping cost based on weight and distance."""
    base_rate = 0.50 * weight + 0.10 * distance
    
    if express:
        base_rate *= 2  # Biaya pengiriman express menjadi dua kali lipat
    
    return round(base_rate, 2)
 
# Kebanyakan pengiriman adalah standar
standard_cost = calculate_shipping(5, 100)
print(f"Standard: ${standard_cost}")
 
# Sesekali ada yang butuh express
express_cost = calculate_shipping(5, 100, express=True)
print(f"Express: ${express_cost}")

Output:

Standard: $12.5
Express: $25.0

Desain ini membuat kasus yang paling umum (pengiriman standar) mudah dipanggil, sambil tetap mendukung kasus yang lebih jarang (express) saat diperlukan.

20.2.4) Banyak Default dan Penimpaan Selektif

Saat sebuah fungsi punya beberapa parameter dengan default, kamu bisa menimpa kombinasi apa pun dari mereka menggunakan argumen keyword:

python
def format_currency(amount, currency="USD", show_symbol=True, decimal_places=2):
    """Format a number as currency."""
    symbols = {"USD": "$", "EUR": "€", "GBP": "£", "JPY": "¥"}
    
    formatted = f"{amount:.{decimal_places}f}"
    
    if show_symbol and currency in symbols:
        formatted = f"{symbols[currency]}{formatted}"
    
    return formatted
 
# Menggunakan semua default
print(format_currency(42.5))
 
# Menimpa hanya currency
print(format_currency(42.5, currency="EUR"))
 
# Menimpa beberapa default
print(format_currency(42.5, currency="JPY", decimal_places=0))

Output:

$42.50
€42.50
¥42

Fleksibilitas ini memungkinkan pemanggil menyesuaikan tepat apa yang dibutuhkan sambil menjaga pemanggilan fungsi tetap ringkas.

20.3) Daftar Argumen Panjang Variabel dengan *args

Terkadang kamu ingin fungsi menerima jumlah argumen berapa pun tanpa tahu sebelumnya akan ada berapa. Python menyediakan *args untuk tujuan ini.

20.3.1) Memahami *args

Sintaks *args dalam daftar parameter mengumpulkan semua argumen positional tambahan menjadi sebuah tuple. Nama args adalah konvensi (singkatan dari "arguments"), tetapi kamu bisa memakai nama parameter valid apa pun setelah tanda bintang.

python
def calculate_total(*numbers):
    """Calculate the sum of any number of values."""
    total = 0
    for num in numbers:
        total += num
    return total
 
# Bisa dengan jumlah argumen berapa pun
print(calculate_total(10))
print(calculate_total(10, 20))
print(calculate_total(10, 20, 30, 40))
print(calculate_total())

Output:

10
30
100
0

Di dalam fungsi, numbers adalah tuple yang berisi semua argumen positional yang dioper ke fungsi. Saat tidak ada argumen yang diberikan, itu adalah tuple kosong.

20.3.2) Menggabungkan Parameter Biasa dengan *args

Kamu bisa punya parameter biasa sebelum *args. Parameter biasa mengonsumsi beberapa argumen pertama, dan *args mengumpulkan sisanya:

python
def create_team(team_name, *members):
    """Create a team with a name and any number of members."""
    member_list = ", ".join(members)
    return f"Team {team_name}: {member_list}"
 
# Argumen pertama masuk ke team_name, sisanya masuk ke members
print(create_team("Alpha", "Alice", "Bob"))
print(create_team("Beta", "Carol"))
print(create_team("Gamma", "Dave", "Eve", "Frank", "Grace"))

Output:

Team Alpha: Alice, Bob
Team Beta: Carol
Team Gamma: Dave, Eve, Frank, Grace

Argumen pertama ("Alpha", "Beta", atau "Gamma") ditetapkan ke team_name, dan semua argumen sisanya dikumpulkan ke dalam tuple members.

20.4) Parameter Keyword-Only dan **kwargs

Python menyediakan dua mekanisme tambahan untuk menangani argumen: parameter keyword-only dan **kwargs untuk mengumpulkan argumen keyword yang sewenang-wenang.

20.4.1) Parameter Keyword-Only

Parameter keyword-only harus ditentukan menggunakan argumen keyword—parameter ini tidak bisa dioper secara positional. Kamu membuatnya dengan menempatkannya setelah * atau setelah *args dalam daftar parameter.

python
def create_account(username, *, email, age):
    """Create an account. Email and age must be specified by name."""
    return {
        "username": username,
        "email": email,
        "age": age
    }
 
# Benar: email dan age ditentukan dengan keyword
account = create_account("alice", email="alice@example.com", age=28)
print(account)
 
# Tidak valid: mencoba mengoper email dan age secara positional
# account = create_account("bob", "bob@example.com", 30)
# TypeError: create_account() takes 1 positional argument but 3 were given

Output:

{'username': 'alice', 'email': 'alice@example.com', 'age': 28}

Tanda * dalam daftar parameter bertindak sebagai pemisah. Segala sesuatu setelahnya harus dioper sebagai argumen keyword. Ini berguna saat kamu ingin memaksa pemanggil agar eksplisit tentang parameter tertentu, sehingga kode lebih mudah dibaca dan lebih kecil kemungkinan salah.

Kamu juga bisa menggabungkan parameter biasa, *args, dan parameter keyword-only:

python
def log_event(event_type, *details, severity="INFO", timestamp=None):
    """Log an event with optional details and metadata."""
    # Kita akan mempelajari modul datetime secara detail di Bab 39,
    # tapi untuk sekarang, cukup tahu bahwa baris-baris ini mengambil waktu saat ini
    # dan memformatnya sebagai string timestamp
    from datetime import datetime
    
    if timestamp is None:
        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    
    details_str = " | ".join(details)
    return f"[{timestamp}] {severity}: {event_type} - {details_str}"
 
# event_type adalah positional, details dikumpulkan oleh *details,
# severity dan timestamp adalah keyword-only
print(log_event("Login", "User: alice", "IP: 192.168.1.1"))
print(log_event("Error", "Database connection failed", severity="ERROR"))

Output (timestamp akan bervariasi tergantung kapan kamu menjalankan kode):

[2025-12-18 19:29:16] INFO: Login - User: alice | IP: 192.168.1.1
[2025-12-18 19:29:16] ERROR: Error - Database connection failed

20.4.2) Memahami **kwargs

Sintaks **kwargs mengumpulkan semua argumen keyword tambahan menjadi sebuah dictionary. Seperti args, nama kwargs adalah konvensi (singkatan dari "keyword arguments"), tetapi kamu bisa memakai nama valid apa pun setelah tanda bintang ganda.

python
def create_product(**attributes):
    """Create a product with any number of attributes."""
    product = {}
    for key, value in attributes.items():
        product[key] = value
    return product
 
# Oper argumen keyword apa pun yang kamu mau
laptop = create_product(name="Laptop", price=999.99, brand="TechCorp", in_stock=True)
print(laptop)
 
phone = create_product(name="Phone", price=699.99, color="Black")
print(phone)

Output:

{'name': 'Laptop', 'price': 999.99, 'brand': 'TechCorp', 'in_stock': True}
{'name': 'Phone', 'price': 699.99, 'color': 'Black'}

Di dalam fungsi, attributes adalah dictionary di mana key adalah nama parameter dan value adalah argumen yang dioper.

20.4.3) Menggabungkan Parameter Biasa, *args, dan **kwargs

Kamu bisa menggunakan semua mekanisme ini bersama-sama, tetapi mereka harus muncul dalam urutan tertentu:

  1. Parameter positional biasa
  2. *args (jika ada)
  3. Parameter keyword-only (jika ada)
  4. **kwargs (jika ada)
python
def complex_function(required, *args, keyword_only, **kwargs):
    """Demonstrate all parameter types together."""
    print(f"Required: {required}")
    print(f"Args: {args}")
    print(f"Keyword-only: {keyword_only}")
    print(f"Kwargs: {kwargs}")
 
complex_function(
    "value1",           # required
    "value2", "value3", # args
    keyword_only="kw",  # keyword_only
    extra1="e1",        # kwargs
    extra2="e2"         # kwargs
)

Output:

Required: value1
Args: ('value2', 'value3')
Keyword-only: kw
Kwargs: {'extra1': 'e1', 'extra2': 'e2'}

Fleksibilitas ini kuat, tetapi sebaiknya digunakan dengan bijak. Kebanyakan fungsi tidak membutuhkan semua mekanisme ini.

20.4.4) Kasus Penggunaan Praktis: Fungsi Konfigurasi

Penggunaan umum untuk **kwargs adalah membuat fungsi yang menerima opsi konfigurasi:

python
def connect_to_database(host, port, **options):
    """Connect to a database with flexible configuration options."""
    connection_string = f"Connecting to {host}:{port}"
    
    # Proses opsi tambahan apa pun
    if options.get("ssl"):
        connection_string += " with SSL"
    
    if options.get("timeout"):
        connection_string += f" (timeout: {options['timeout']}s)"
    
    if options.get("pool_size"):
        connection_string += f" (pool size: {options['pool_size']})"
    
    return connection_string
 
# Koneksi dasar
print(connect_to_database("localhost", 5432))
 
# Dengan SSL
print(connect_to_database("db.example.com", 5432, ssl=True))
 
# Dengan beberapa opsi
print(connect_to_database("db.example.com", 5432, ssl=True, timeout=30, pool_size=10))

Output:

Connecting to localhost:5432
Connecting to db.example.com:5432 with SSL
Connecting to db.example.com:5432 with SSL (timeout: 30s) (pool size: 10)

Pola ini memungkinkan fungsi menerima jumlah parameter konfigurasi opsional berapa pun tanpa mendefinisikannya semua secara eksplisit dalam daftar parameter.

Positional

Positional Tambahan

Keyword-Only

Keyword Tambahan

Pemanggilan Fungsi

Jenis Parameter?

Parameter Biasa

Tuple *args

Parameter Keyword-Only

Dict **kwargs

Ditetapkan berdasarkan Posisi

Dikumpulkan menjadi Tuple

Harus Pakai Nama

Dikumpulkan menjadi Dict

20.5) Unpacking Argumen Saat Memanggil Fungsi

Sama seperti *args dan **kwargs mengumpulkan argumen saat mendefinisikan fungsi, kamu bisa menggunakan * dan ** untuk membongkar (unpack) koleksi saat memanggil fungsi.

20.5.1) Unpacking Sequence dengan *

Operator * membongkar sebuah sequence (list, tuple, dll.) menjadi argumen positional terpisah:

python
def calculate_rectangle_area(width, height):
    """Calculate the area of a rectangle."""
    return width * height
 
# Alih-alih mengoper argumen satu per satu
dimensions = [5, 10]
area = calculate_rectangle_area(dimensions[0], dimensions[1])
print(area)
 
# Bongkar list secara langsung
area = calculate_rectangle_area(*dimensions)
print(area)

Output:

50
50

Saat kamu menulis *dimensions, Python membongkar list [5, 10] menjadi dua argumen terpisah, seolah-olah kamu menulis calculate_rectangle_area(5, 10).

Ini bekerja dengan iterable apa pun:

python
def format_name(first, middle, last):
    """Format a full name."""
    return f"{first} {middle} {last}"
 
# Unpacking sebuah tuple
name_tuple = ("John", "Q", "Public")
print(format_name(*name_tuple))
 
# Unpacking sebuah list
name_list = ["Jane", "M", "Doe"]
print(format_name(*name_list))
 
# Bahkan unpacking sebuah string (setiap karakter menjadi argumen)
# Ini hanya bekerja jika fungsi mengharapkan jumlah argumen yang tepat
def show_first_three(a, b, c):
    return f"{a}, {b}, {c}"
 
print(show_first_three(*"ABC"))

Output:

John Q Public
Jane M Doe
A, B, C

20.5.2) Unpacking Dictionary dengan **

Operator ** membongkar sebuah dictionary menjadi argumen keyword:

python
def create_user(username, email, age):
    """Create a user profile."""
    return f"User: {username}, Email: {email}, Age: {age}"
 
# Dictionary dengan key yang cocok dengan nama parameter
user_data = {
    "username": "alice",
    "email": "alice@example.com",
    "age": 28
}
 
# Bongkar dictionary
profile = create_user(**user_data)
print(profile)

Output:

User: alice, Email: alice@example.com, Age: 28

Saat kamu menulis **user_data, Python membongkar dictionary menjadi argumen keyword, setara dengan:

python
create_user(username="alice", email="alice@example.com", age=28)

Key pada dictionary harus cocok dengan nama parameter fungsi, atau kamu akan mendapat error:

python
# Tidak valid: key dictionary tidak cocok dengan nama parameter
invalid_data = {"name": "bob", "email": "bob@example.com", "age": 30}
# profile = create_user(**invalid_data)
# TypeError: create_user() got an unexpected keyword argument 'name'

20.5.3) Menggabungkan Unpacking dengan Argumen Biasa

Kamu bisa mencampur argumen yang dibongkar dengan argumen biasa:

python
def calculate_total(base_price, tax_rate, discount):
    """Calculate total price after tax and discount."""
    subtotal = base_price * (1 + tax_rate)
    total = subtotal * (1 - discount)
    return round(total, 2)
 
# Sebagian argumen biasa, sebagian dibongkar
pricing = [0.08, 0.10]  # tax_rate dan discount
total = calculate_total(100, *pricing)
print(total)

Output:

97.2

Kamu juga bisa membongkar beberapa koleksi dalam satu pemanggilan:

python
def create_full_address(street, city, state, zip_code, country):
    """Create a complete address."""
    return f"{street}, {city}, {state} {zip_code}, {country}"
 
street_address = ["123 Main St", "Springfield"]
location_details = ["IL", "62701", "USA"]
 
address = create_full_address(*street_address, *location_details)
print(address)

Output:

123 Main St, Springfield, IL 62701, USA

20.5.4) Contoh Praktis: Pemanggilan Fungsi yang Fleksibel

Unpacking sangat berguna saat bekerja dengan data dari sumber eksternal:

python
def send_email(recipient, subject, body, cc=None, bcc=None):
    """Send an email with optional CC and BCC."""
    message = f"To: {recipient}\nSubject: {subject}\n\n{body}"
    
    if cc:
        message += f"\nCC: {cc}"
    if bcc:
        message += f"\nBCC: {bcc}"
    
    return message
 
# Data email dari file konfigurasi atau database
email_config = {
    "recipient": "user@example.com",
    "subject": "Welcome",
    "body": "Thank you for signing up!",
    "cc": "manager@example.com"
}
 
# Bongkar konfigurasi secara langsung
result = send_email(**email_config)
print(result)

Output:

To: user@example.com
Subject: Welcome
 
Thank you for signing up!
CC: manager@example.com

Pola ini memudahkan untuk mengoper argumen fungsi sebagai struktur data, yang umum saat membangun API atau memproses file konfigurasi.

operator *

operator **

Koleksi

Jenis Unpacking

Unpacking Sequence

Unpacking Dictionary

List/Tuple → Argumen Positional

Dict → Argumen Keyword

Pemanggilan Fungsi

20.6) Jebakan Argumen Default yang Mutable (Kenapa Default List Bertahan)

Salah satu jebakan Python yang paling terkenal melibatkan penggunaan objek mutable (seperti list atau dictionary) sebagai nilai default parameter. Memahami masalah ini sangat penting untuk menulis fungsi yang benar.

20.6.1) Masalahnya: Default Mutable yang Dibagikan

Pertimbangkan fungsi yang tampak tidak berbahaya ini:

python
def add_student(name, grades=[]):
    """Add a student with their grades."""
    grades.append(name)
    return grades
 
# Pemanggilan pertama
students1 = add_student("Alice")
print(students1)
 
# Pemanggilan kedua - berharap list baru
students2 = add_student("Bob")
print(students2)
 
# Pemanggilan ketiga
students3 = add_student("Carol")
print(students3)

Output:

['Alice']
['Alice', 'Bob']
['Alice', 'Bob', 'Carol']

Perilaku ini mengejutkan banyak programmer. Setiap pemanggilan add_student() tanpa memberikan argumen grades menggunakan objek list yang sama, bukan yang baru. List tersebut bertahan antar pemanggilan fungsi, terus menumpuk nilai.

20.6.2) Kenapa Ini Terjadi: Nilai Default Dibuat Sekali

Kunci untuk memahami perilaku ini adalah mengetahui kapan nilai default dibuat. Python mengevaluasi nilai default parameter sekali, saat fungsi didefinisikan, bukan setiap kali fungsi dipanggil.

python
def demonstrate_default_creation():
    """Show when defaults are created."""
    print("Function defined!")
 
def use_default(value=demonstrate_default_creation()):
    """Use a default that calls a function."""
    return value
 
# Pesan dicetak saat fungsi DIDEFINISIKAN, bukan saat dipanggil

Output:

Function defined!

Saat Python menemui baris def use_default, Python mengevaluasi parameter default value=demonstrate_default_creation(). Ini memanggil demonstrate_default_creation(), yang langsung mencetak "Function defined!". Pemanggilan use_default() setelah itu tidak mengevaluasi default lagi, jadi tidak ada yang tercetak tambahan.

Saat Python menemui def add_student(name, grades=[]):, Python membuat sebuah objek list kosong dan menyimpannya sebagai nilai default untuk grades. Setiap pemanggilan berikutnya yang tidak menyediakan argumen grades akan memakai objek list yang sama.

Berikut demonstrasi yang lebih jelas menggunakan identitas objek:

python
def show_list_identity(items=[]):
    """Show that the same list object is reused."""
    print(f"List ID: {id(items)}")
    items.append("item")
    return items
 
# Setiap pemanggilan memakai objek list yang sama (ID yang sama)
show_list_identity()
show_list_identity()
show_list_identity()

Output:

List ID: 140234567890123
List ID: 140234567890123
List ID: 140234567890123

Angka ID yang tepat akan bervariasi di sistem kamu, tetapi perhatikan bahwa ketiga pemanggilan menunjukkan nilai ID yang sama, membuktikan bahwa mereka memakai objek list yang sama. Fungsi id() mengembalikan pengenal unik untuk setiap objek di memori—kalau ID-nya sama, itu objek yang sama.

20.6.3) Pola yang Benar: Gunakan None sebagai Default

Solusi standar adalah menggunakan None sebagai default dan membuat objek mutable baru di dalam fungsi:

python
def add_student_correct(name, grades=None):
    """Add a student with their grades (correct version)."""
    if grades is None:
        grades = []  # Buat list BARU setiap kali
    
    grades.append(name)
    return grades
 
# Sekarang setiap pemanggilan mendapat list masing-masing
students1 = add_student_correct("Alice")
print(students1)
 
students2 = add_student_correct("Bob")
print(students2)
 
students3 = add_student_correct("Carol")
print(students3)

Output:

['Alice']
['Bob']
['Carol']

Pola ini bekerja karena None bersifat immutable dan list baru dibuat di dalam body fungsi setiap kali grades adalah None.

20.6.4) Masalah yang Sama pada Dictionary

Masalah ini memengaruhi semua tipe mutable, bukan hanya list:

python
# SALAH: default dictionary
def create_config_wrong(key, value, config={}):
    """Create a configuration (BUGGY VERSION)."""
    config[key] = value
    return config
 
config1 = create_config_wrong("theme", "dark")
print(config1)
 
config2 = create_config_wrong("language", "en")
print(config2)
 
print("---")
 
# BENAR: None sebagai default
def create_config_correct(key, value, config=None):
    """Create a configuration (CORRECT VERSION)."""
    if config is None:
        config = {}
    
    config[key] = value
    return config
 
config1 = create_config_correct("theme", "dark")
print(config1)
 
config2 = create_config_correct("language", "en")
print(config2)

Output:

{'theme': 'dark'}
{'theme': 'dark', 'language': 'en'}
---
{'theme': 'dark'}
{'language': 'en'}

20.6.5) Ringkasan: Aturan Emas

Jangan pernah memakai objek mutable (list, dictionary, set) sebagai nilai default parameter. Selalu gunakan None dan buat objek mutable di dalam fungsi:

python
# ❌ SALAH
def function(items=[]):
    pass
 
# ✅ BENAR
def function(items=None):
    if items is None:
        items = []
    # Sekarang gunakan items dengan aman

Pola ini memastikan setiap pemanggilan fungsi mendapatkan objek mutable independen miliknya sendiri, mencegah bug misterius saat data “bocor” antar pemanggilan.


Dalam bab ini, kita sudah mengeksplorasi sistem parameter dan argumen Python yang fleksibel secara mendalam. Kamu sudah belajar cara menggunakan argumen positional dan keyword, menyediakan nilai default, menangani jumlah argumen yang bervariasi dengan *args dan **kwargs, membongkar (unpack) koleksi saat memanggil fungsi, dan menghindari jebakan argumen default yang mutable.

Mekanisme ini memberi kamu alat yang kuat untuk merancang antarmuka fungsi yang fleksibel sekaligus mudah digunakan. Saat kamu menulis lebih banyak fungsi, kamu akan mengembangkan intuisi tentang pola parameter mana yang paling cocok untuk situasi yang berbeda. Kuncinya adalah menyeimbangkan fleksibilitas dengan kejelasan—buat fungsi kamu mudah dipanggil dengan benar dan sulit dipanggil dengan salah.

© 2025. Primesoft Co., Ltd.
support@primesoft.ai