Dasar

Fungsi di Python: def, return, argumen, *args dan **kwargs, lambda dan anotasi tipe

Diperbarui: · Skillaria.Top

Fungsi di Python adalah blok kode bernama yang dideklarasikan dengan kata kunci def, dipanggil dengan nama dan tanda kurung, dan mengembalikan hasil lewat return; tanpa return, fungsi mengembalikan None. Argumen diberikan menurut urutan atau nama, *args mengumpulkan nilai posisional tambahan menjadi tuple, **kwargs mengumpulkan argumen bernama menjadi dict, dan lambda membuat fungsi anonim pendek dari satu ekspresi.

Fungsi di Python adalah potongan kode bernama yang bisa dipanggil berkali-kali dengan data masukan yang berbeda. Ia dideklarasikan dengan kata def, menerima nilai lewat parameter, dan mengembalikan hasil dengan return. Fungsi adalah cara utama untuk mengubah skrip panjang menjadi langkah-langkah yang jelas dan bisa diuji.

Cara mendeklarasikan fungsi: def python

Deklarasi fungsi diawali def, lalu nama, parameter dalam kurung, dan titik dua. Isinya ditulis menjorok empat spasi — indentasi di Python bukan hiasan, melainkan bagian dari sintaks.

def greet(name):
    """Mengembalikan sapaan untuk pengguna."""
    return f"Halo, {name}!"

print(greet("Rina"))   # Halo, Rina!

String dengan tanda kutip tiga tepat setelah judul disebut docstring, yaitu dokumentasi fungsi. Ia ditampilkan oleh help(greet) dan oleh petunjuk di editor. Menurut konvensi PEP 8, nama fungsi ditulis dalam snake_case: add_expense, get_rate.

Baris def greet(name): disebut signature fungsi: nama plus daftar parameter (dan anotasinya jika ada). Dari signature, pembaca langsung paham cara memanggil fungsi tanpa melihat isinya.

Apa yang dilakukan return di Python

return mengakhiri fungsi dan memberikan nilai kepada pemanggilnya. Kode setelah return yang sudah dijalankan tidak akan dieksekusi. Jika tidak ada return, atau ditulis tanpa nilai, fungsi mengembalikan None.

def area(w, h):
    w * h          # hasilnya dihitung lalu dibuang

print(area(3, 4))  # None

def area(w, h):
    return w * h

print(area(3, 4))  # 12

Lupa menulis return adalah salah satu kesalahan paling umum pemula: fungsinya «jalan», tetapi mengembalikan None, dan masalahnya baru terasa di baris berikutnya. Fungsi juga bisa mengembalikan beberapa nilai — sebenarnya itu satu tuple yang mudah dibongkar:

def min_max(numbers):
    return min(numbers), max(numbers)

low, high = min_max([4, 1, 9])
print(low, high)   # 1 9

Return dini membantu mengurangi lapisan bersarang: kasus khusus disingkirkan dulu, baru logika utama ditulis.

def discount(price, is_member):
    if price <= 0:
        return 0
    if not is_member:
        return price
    return price * 0.9

Argumen fungsi di Python: posisional dan bernama

Parameter adalah nama yang ditulis di deklarasi fungsi, sedangkan argumen adalah nilai yang diberikan saat pemanggilan. Argumen bisa diberikan menurut urutan (posisional) atau menurut nama (bernama). Argumen bernama membuat pemanggilan lebih mudah dibaca, dan urutannya tidak lagi penting.

def add_expense(title, amount, category="lainnya"):
    return {"title": title, "amount": amount, "category": category}

add_expense("Kopi", 250)                          # posisional
add_expense(amount=250, title="Kopi")             # menurut nama
add_expense("Taksi", 600, category="transport")   # campuran

Parameter dengan nilai bawaan bersifat opsional. Aturannya: parameter dengan nilai bawaan ditulis setelah parameter wajib, dan saat pemanggilan argumen posisional ditulis sebelum argumen bernama. Jika tidak, Python menampilkan SyntaxError.

Jebakan: nilai bawaan yang bisa diubah

Nilai bawaan dihitung sekali — saat baris def dieksekusi, bukan setiap kali fungsi dipanggil. Jika nilainya list atau dict, objek itu akan dipakai bersama oleh semua pemanggilan.

def add_item(item, acc=[]):
    acc.append(item)
    return acc

print(add_item(1))  # [1]
print(add_item(2))  # [1, 2] — list mengingat pemanggilan sebelumnya

Cara yang benar adalah memakai None sebagai nilai bawaan dan membuat objek baru di dalam fungsi:

def add_item(item, acc=None):
    if acc is None:
        acc = []
    acc.append(item)
    return acc

*args dan **kwargs: jumlah argumen bebas

Tanda bintang di depan parameter mengumpulkan semua argumen posisional yang tersisa menjadi tuple (tuple), dan dua tanda bintang mengumpulkan semua argumen bernama menjadi dict (dict). Nama args dan kwargs hanya kebiasaan; yang penting adalah tanda bintangnya.

def total(*args):
    return sum(args)

print(total(100, 250, 40))   # 390

def make_user(name, **kwargs):
    user = {"name": name}
    user.update(kwargs)
    return user

print(make_user("Rina", city="Bandung", age=30))
# {'name': 'Rina', 'city': 'Bandung', 'age': 30}

Tanda bintang yang sama juga bekerja sebaliknya — saat pemanggilan, ia membongkar urutan atau dict menjadi argumen:

values = [3, 4]
print(pow(*values))          # 81

opts = {"sep": " | ", "end": "\n"}
print("a", "b", **opts)      # a | b

Parameter hanya posisional dan hanya bernama

Garis miring / dan tanda bintang * dalam daftar parameter bekerja seperti palang: semua yang ada sebelum / hanya bisa diberikan menurut urutan (sintaksnya hadir sejak Python 3.8, PEP 570), dan semua yang ada setelah * hanya bisa diberikan menurut nama.

def convert(amount, /, *, rate, currency="USD"):
    return round(amount / rate, 2), currency

convert(100, rate=90.5)          # (1.1, 'USD')
convert(amount=100, rate=90.5)   # TypeError: amount hanya boleh diberikan secara posisional
convert(100, 90.5)               # TypeError: rate hanya boleh diberikan dengan nama

Parameter yang hanya bernama melindungi dari kebingungan pada pemanggilan seperti convert(100, 90.5, "EUR"), di mana tidak jelas apa nilai apa.

Ruang lingkup: aturan LEGB

Python mencari nama variabel secara berjenjang: Local (di dalam fungsi) → Enclosing (di fungsi luar) → Global (di tingkat modul) → Built-in (nama bawaan seperti len). Membaca variabel global di dalam fungsi boleh dilakukan, tetapi untuk memberinya nilai baru diperlukan deklarasi global.

limit = 1000

def check(amount):
    return amount > limit    # membaca global — boleh

def raise_limit():
    global limit
    limit = 2000             # tanpa global, akan terbentuk variabel lokal baru

Dalam praktiknya, hindari global: fungsi yang mengubah keadaan di luar dirinya sulit diuji. Lebih baik terima nilai lewat argumen dan kembalikan hasilnya.

Fungsi bersarang dan closure

Fungsi bisa dideklarasikan di dalam fungsi lain. Fungsi bersarang melihat variabel fungsi luarnya bahkan setelah fungsi luar selesai — inilah yang disebut closure. Untuk mengubah variabel seperti itu digunakan nonlocal.

def make_counter():
    count = 0
    def counter():
        nonlocal count
        count += 1
        return count
    return counter

c = make_counter()
print(c(), c(), c())   # 1 2 3

Closure menjadi dasar decorator dan pabrik fungsi.

Fungsi juga objek

Di Python, fungsi adalah objek biasa: bisa disimpan di variabel, dikirim ke fungsi lain, dikembalikan dari fungsi, atau disimpan di dict. Fungsi punya atribut seperti __name__, __doc__, __defaults__, dan __annotations__.

def double(x):
    return x * 2

f = double
print(f(5), f.__name__)                # 10 double
print(list(map(double, [1, 2, 3])))   # [2, 4, 6]

Lambda di Python: fungsi anonim

Fungsi lambda adalah fungsi pendek tanpa nama yang badannya hanya satu ekspresi. Hasil ekspresi dikembalikan secara otomatis, sehingga return tidak ditulis.

square = lambda x: x ** 2
print(square(4))   # 16

expenses = [("Kopi", 250), ("Taksi", 600), ("Makan siang", 450)]
expenses.sort(key=lambda e: e[1], reverse=True)
print(expenses)  # [('Taksi', 600), ('Makan siang', 450), ('Kopi', 250)]

print(list(filter(lambda n: n % 2 == 0, range(10))))  # [0, 2, 4, 6, 8]

Lambda cocok sebagai argumen singkat untuk sorted, max, map, dan filter. Menyimpan lambda ke variabel seperti square di atas tidak dianjurkan PEP 8: jika fungsi perlu nama, tulis def — ia akan punya __name__ yang normal di traceback dan tempat untuk docstring.

deflambda
Namaadatidak ada (<lambda>)
Badansejumlah instruksisatu ekspresi
returneksplisitimplisit
Docstring, anotasiadatidak
Cocok untuksegala keperluankey atau callback singkat

Anotasi tipe: petunjuk, bukan pemeriksaan

Anotasi menjelaskan tipe parameter dan hasil yang diharapkan. Python sendiri tidak memeriksanya saat program berjalan: fungsi dengan x: int tetap menerima string. Pemeriksaan dilakukan oleh alat luar — mypy, pyright, ty — dan oleh editor yang menyoroti kesalahan sebelum program dijalankan.

def add_expense(title: str, amount: float, category: str = "lainnya") -> dict[str, object]:
    return {"title": title, "amount": amount, "category": category}

def area(w: float, h: float) -> float:
    w * h   # mypy: Missing return statement

Pemeriksaan bisa dijalankan tanpa instalasi dengan uvx mypy .. Contoh di atas memperlihatkan manfaat anotasi: return yang terlupa pada fungsi -> float langsung tertangkap analisis.

Sejak Python 3.12 (PEP 695), fungsi generik ditulis tanpa TypeVar: parameter tipe ditulis dalam kurung siku, dan alias tipe dideklarasikan dengan kata type.

def first[T](xs: list[T]) -> T:
    return xs[0]

type Money = int | float

Di Python 3.14 (PEP 649) anotasi menjadi malas: ia dievaluasi saat pertama kali diakses, sehingga merujuk kelas yang dideklarasikan di bawah bisa dilakukan tanpa tanda kutip, dan from __future__ import annotations tidak lagi diperlukan.

«Tidak diberikan» atau «diberikan None»: sentinel di 3.15

Nilai bawaan None tidak memungkinkan kita membedakan «argumen tidak diberikan» dan «sengaja diberikan None». Bertahun-tahun masalah ini diselesaikan dengan penanda buatan sendiri:

_MISSING = object()

def get_rate(currency, default=_MISSING):
    rates = {"USD": 90.5}
    if currency in rates:
        return rates[currency]
    if default is _MISSING:
        raise KeyError(currency)
    return default

Di Python 3.15 hadir fungsi bawaan sentinel (PEP 661): MISSING = sentinel("MISSING") membuat penanda unik dengan repr yang jelas, yang tetap sama saat disalin, bisa di-serialisasi lewat pickle, dan bisa dipakai dalam anotasi seperti float | MISSING. Di versi lama, pola dengan object() tetap berfungsi.

Kesalahan umum dengan fungsi

  • Lupa return — fungsi mengembalikan None.
  • Lupa tanda kurung — print(greet) menampilkan objek fungsi, bukan hasil pemanggilan.
  • Nilai bawaan yang bisa diubah — satu list dipakai bersama oleh semua pemanggilan.
  • Jumlah argumen salah — TypeError: greet() missing 1 required positional argument: 'name'.
  • Nama bertabrakan dengan bawaan — fungsi bernama list atau sum akan menutupi fungsi bawaan.

Ringkasan

Fungsi di Python dideklarasikan dengan def, mengembalikan hasil lewat return, dan menerima argumen menurut urutan atau nama. *args dan **kwargs memberi fleksibilitas, / dan * memberi ketegasan pada pemanggilan, lambda memberi keringkasan untuk fungsi sekali pakai, dan anotasi tipe bersama mypy menangkap kesalahan sebelum program dijalankan. Dalam kursus Python, topik ini dipraktikkan dengan cara memecah pencatat pengeluaran menjadi fungsi-fungsi beranotasi yang diperiksa mypy.

Pertanyaan umum

Apa beda parameter dan argumen?

Parameter adalah nama di deklarasi fungsi, argumen adalah nilai konkret yang diberikan saat pemanggilan. Pada def greet(name), name adalah parameter; pada greet("Rina"), string "Rina" adalah argumen.

Bisakah fungsi dipanggil sebelum dideklarasikan?

Di tingkat modul tidak bisa: baris def harus sudah dieksekusi sebelum pemanggilan, jika tidak akan terjadi NameError. Namun di dalam fungsi lain, kita bisa memanggil fungsi yang dideklarasikan di bawahnya, asalkan pemanggilan terjadi setelah deklarasinya dieksekusi.

Berapa banyak nilai yang bisa dikembalikan fungsi?

Secara formal satu, tetapi nilai itu bisa berupa tuple: return a, b mengembalikan tuple berisi dua elemen, yang bisa dibongkar menjadi x, y = f().

Apakah anotasi tipe wajib?

Tidak, Python berjalan tanpa anotasi. Namun pada kode yang dibaca orang lain, anotasi memudahkan perawatan dan memungkinkan mypy atau pyright menemukan kesalahan sebelum program dijalankan.

Bisakah lambda memakai if?

Hanya ekspresi kondisional: lambda x: "genap" if x % 2 == 0 else "ganjil". Instruksi, perulangan, dan penugasan tidak diperbolehkan di dalam lambda.

Pelajari topik ini lewat video

Topik ini dibahas mendalam dengan praktik di kursus “Python 3.15: от новичка до профи”.

Ke kursus