Pada Chapter Komentar dan Docstring kita sudah mengenal docstring sebagai string pertama pada sebuah module, function, atau class. Bentuk satu kalimat tersebut cukup untuk skrip kecil, tetapi ketika kode dibaca oleh rekan tim — atau oleh tool seperti help() dan Sphinx — docstring perlu struktur yang lebih kaya: parameter apa saja yang diterima, nilai apa yang dikembalikan, exception apa yang bisa terbang, dan contoh pemakaian yang bisa diverifikasi. Chapter ini membahas gaya penulisan docstring yang dipakai industri serta cara menjadikan contoh di dalam docstring sebagai test otomatis.

Gaya Docstring yang Sering Dipakai #

Docstring adalah teks bebas, jadi Python tidak memaksa format tertentu. Komunitas Python justru bersepakat lewat tiga gaya populer, dan semuanya menempel pada function yang sama:

python
def total_setelah_pajak(harga: float, tarif_pajak: float) -> float:
    """Hitung harga akhir setelah ditambah pajak.

    Args:
        harga: harga barang sebelum pajak, dalam rupiah.
        tarif_pajak: tarif pajak sebagai pecahan, misal 0.11 untuk 11%.

    Returns:
        Harga akhir setelah pajak.
    """
    return harga * (1 + tarif_pajak)

Gaya di atas disebut gaya Google: ringkas, rata kiri, dan mudah dibaca langsung di editor. Gaya NumPy dan reST menandai bagian yang sama dengan cara berbeda:

python
def total_setelah_pajak(harga: float, tarif_pajak: float) -> float:
    """Hitung harga akhir setelah ditambah pajak.

    Parameters
    ----------
    harga : float
        Harga barang sebelum pajak, dalam rupiah.
    tarif_pajak : float
        Tarif pajak sebagai pecahan, misal 0.11 untuk 11%.

    Returns
    -------
    float
        Harga akhir setelah pajak.
    """
    return harga * (1 + tarif_pajak)
python
def total_setelah_pajak(harga: float, tarif_pajak: float) -> float:
    """Hitung harga akhir setelah ditambah pajak.

    :param harga: harga barang sebelum pajak, dalam rupiah.
    :param tarif_pajak: tarif pajak sebagai pecahan, misal 0.11 untuk 11%.
    :returns: harga akhir setelah pajak.
    """
    return harga * (1 + tarif_pajak)
GayaPenanda khasLazim dipakai
GoogleArgs:, Returns:, Raises:banyak perusahaan dan proyek aplikasi
NumPyParameters, garis ----------proyek ilmiah: NumPy, pandas, scikit-learn
reST (Sphinx):param x:, :returns:proyek yang memakai Sphinx klasik
Polosparagraf bebas tanpa bagianskrip kecil, internal

Semua gaya ini sah bagi interpreter Python — perbedaannya hanya soal konvensi. Pilih satu gaya untuk seluruh proyek, lalu pertahankan konsistensinya; pembaca yang sudah hapal satu docstring Anda akan mengharapkan format yang sama di tempat lain.

Bagian Inti Docstring Google Style #

Kita jadikan gaya Google sebagai gaya utama karena strukturnya paling ringkas dibaca. Empat bagian yang paling sering dibutuhkan — ringkasan, Args, Returns, Raises — terlihat pada contoh berikut:

python
def transfer_saldo(saldo: float, jumlah: float) -> float:
    """Kurangi saldo sebesar jumlah transfer.

    Transfer hanya boleh dilakukan bila saldo mencukupi.
    Pemotongan terjadi sekali per pemanggilan.

    Args:
        saldo: saldo rekening saat ini, dalam rupiah.
        jumlah: nominal yang akan ditransfer, harus positif.

    Returns:
        Saldo baru setelah pemotongan.

    Raises:
        ValueError: jika jumlah tidak lebih besar dari nol.
        RuntimeError: jika saldo tidak mencukupi.
    """
    if jumlah <= 0:
        raise ValueError("jumlah transfer harus positif")
    if jumlah > saldo:
        raise RuntimeError("saldo tidak mencukupi")
    return saldo - jumlah


help(transfer_saldo)

Output yang Dihasilkan:

text
Help on function transfer_saldo in module __main__:

transfer_saldo(saldo: float, jumlah: float) -> float
    Kurangi saldo sebesar jumlah transfer.

    Transfer hanya boleh dilakukan bila saldo mencukupi.
    Pemotongan terjadi sekali per pemanggilan.

    Args:
        saldo: saldo rekening saat ini, dalam rupiah.
        jumlah: nominal yang akan ditransfer, harus positif.

    Returns:
        Saldo baru setelah pemotongan.

    Raises:
        ValueError: jika jumlah tidak lebih besar dari nol.
        RuntimeError: jika saldo tidak mencukupi.

Mari kita bedah strukturnya:

  1. Baris pertama (Kurangi saldo ...): ringkasan satu baris dalam bentuk perintah — menjelaskan apa yang dilakukan function bila dijalankan.
  2. Baris ketiga dan keempat: paragraf tambahan untuk kontrak yang tidak muat di satu baris — syarat dan jaminan perilaku.
  3. Bagian Args: setiap parameter dijelaskan satu per satu, termasuk satuan dan syarat nilainya.
  4. Bagian Returns: menjelaskan makna nilai kembali, bukan tipe datanya — tipe sudah diumumkan oleh anotasi -> float.
  5. Bagian Raises: mencantumkan exception yang sengaja dilempar beserta kondisi pemicunya, sehingga pemanggil tahu apa yang harus ditangkap.

Menjadikan Contoh sebagai Test dengan doctest #

Bagian docstring yang paling mudah basi adalah contoh pemakaian. Python punya solusi bawaan bernama doctest: contoh berformat REPL di dalam docstring bisa dijalankan ulang sebagai test. Simpan function berikut sebagai file rupiah.py:

python
"""Utilitas format rupiah untuk demo doctest."""


def format_rupiah(nilai: float) -> str:
    """Format angka menjadi teks rupiah.

    Args:
        nilai: angka yang akan diformat.

    Returns:
        Teks dengan pemisah ribuan, contoh "Rp15.000".

    Example:
        >>> format_rupiah(15000)
        'Rp15.000'
        >>> format_rupiah(2500)
        'Rp2.500'
    """
    return f"Rp{nilai:,.0f}".replace(",", ".")


if __name__ == "__main__":
    import doctest
    doctest.testmod()

Jalankan module doctest dengan opsi verbose:

bash
python3 -m doctest rupiah.py -v

Output yang Dihasilkan:

text
Trying:
    format_rupiah(15000)
Expecting:
    'Rp15.000'
ok
Trying:
    format_rupiah(2500)
Expecting:
    'Rp2.500'
ok
1 items had no tests:
    rupiah
1 items passed all tests:
   2 tests in rupiah.format_rupiah
2 tests in 2 items.
2 passed and 0 failed.
Test passed.

Module doctest mengeksekusi tiap baris >>>, membandingkan hasilnya dengan baris di bawahnya, lalu melaporkan ok bila identik. Tanpa -v, doctest hanya bersuara saat ada kegagalan — perilaku yang cocok untuk dijalankan di CI. Lihat apa yang terjadi bila contoh ditulis salah:

text
**********************************************************************
File "rupiah_salah.py", line 8, in rupiah_salah.format_rupiah
Failed example:
    format_rupiah(15000)
Expected:
    'Rp15000'
Got:
    'Rp15.000'
**********************************************************************
1 items had failures:
   1 of   1 in rupiah_salah.format_rupiah
***Test Failed*** 1 failures.

Python menampilkan path lengkap file sebelum nama file; dipangkas di sini agar ringkas. Contoh yang salah langsung tertangkap: docstring berjanji Rp15000, kode menghasilkan Rp15.000. Dengan doctest, contoh dan implementasi tidak akan saling meninggalkan.

Docstring pada Class, Property, dan Module #

Docstring bukan milik function saja. Setiap tingkatan struktur kode punya tempat docstring sendiri, dan help() mengumpulkan semuanya:

python
"""Manajemen rekening tabungan sederhana."""

MINIMAL_SETORAN = 10_000


class Rekening:
    """Representasi satu rekening tabungan.

    Attributes:
        pemilik: nama pemilik rekening.
        saldo: saldo rekening dalam rupiah.
    """

    def __init__(self, pemilik: str, saldo: float) -> None:
        """Simpan identitas pemilik dan saldo awal."""
        self.pemilik = pemilik
        self.saldo = saldo

    @property
    def ringkasan(self) -> str:
        """Teks ringkas untuk ditampilkan pada halaman utama."""
        return f"{self.pemilik}: Rp{self.saldo:,.0f}"

    def setor(self, jumlah: float) -> float:
        """Tambah saldo sebesar jumlah.

        Returns:
            Saldo terbaru setelah setoran.
        """
        self.saldo += jumlah
        return self.saldo


help(Rekening)

Output yang Dihasilkan (dipangkas):

text
Help on class Rekening in module __main__:

class Rekening(builtins.object)
 |  Rekening(pemilik: str, saldo: float) -> None
 |
 |  Representasi satu rekening tabungan.
 |
 |  Attributes:
 |      pemilik: nama pemilik rekening.
 |      saldo: saldo rekening dalam rupiah.
 |
 |  Methods defined here:
 |
 |  setor(self, jumlah: float) -> float
 |      Tambah saldo sebesar jumlah.

Docstring module (Manajemen rekening ...) menjelaskan isi file secara keseluruhan; docstring class menjelaskan konsep yang diwakili class; docstring property dan method menjelaskan tiap perilaku. Pemanggilan help(Rekening) merangkum semuanya dalam satu tampilan.

Lalu apa yang sebaiknya didokumentasikan? Aturan praktisnya: dokumentasikan kontrak publik, bukan hal yang sudah jelas dari namanya.

PrioritasContohAlasan
Wajibfunction dan class publikkontrak bagi pemanggil
Wajibsyarat nilai, satuan, exceptiontidak terlihat dari nama
Sebaiknyamodule utama sebuah packagepintu masuk pembaca
Tidak perlufunction privat _hitung, getter sepelekode sudah bicara sendiri

Docstring yang tertata rapi bukan hanya nyaman dibaca lewat help(). Tool dokumentasi dapat membaca docstring langsung dari kode dan menyusunnya menjadi situs dokumentasi lengkap — kekuatan yang akan kita manfaatkan pada Chapter Dokumentasi dengan Sphinx.