Kita telah melihat pada Section Advanced Data Modeling (Chapter Abstract Base Classes) bahwa ABC memaksa class menandatangani kontrak lewat pewarisan — hubungan tipe dibuktikan dengan nominal: class menyatakan sendiri “saya turunan dari ini”. Namun falsafah asli Python berbeda: yang penting bukan garis keturunan, melainkan “bisa apa”. Function len() tidak peduli class kita mewarisi apa; yang penting method __len__ ada. typing.Protocol membawa duck typing tersebut ke dunia static checking — inilah structural typing.
Dua Gaya Pencocokan Tipe #
| Aspek | Nominal (ABC) | Structural (Protocol) |
|---|---|---|
| Bukti kecocokan | mewarisi class/interface | memiliki method yang dibutuhkan |
| Pendaftaran | eksplisit (class Kucing(Hewan)) | otomatis, tanpa pendaftaran |
| Cocok untuk | kerangka class milik sendiri | batas antar-library, plugin |
| Pemeriksaan | checker & runtime (issubclass) | checker; runtime terbatas |
Dengan Protocol, class tidak perlu tahu sedang dihitung cocok dengan siapa. Cukup bentuknya yang sama, checker mengatakannya cocok.
Mendefinisikan Protocol #
Protocol didefinisikan seperti class yang mewarisi typing.Protocol, berisi deklarasi method tanpa badan:
from typing import Protocol
class Penyapa(Protocol):
def sapa(self, nama: str) -> str: ...
class Sopir:
def sapa(self, nama: str) -> str:
return f"Halo, {nama}! Saya sopir Anda."
class Pelayan:
def sapa(self, nama: str) -> str:
return f"Selamat datang, {nama}!"
def layani(tim: Penyapa, nama: str) -> str:
return tim.sapa(nama)
print(layani(Sopir(), "Budi"))
print(layani(Pelayan(), "Siti"))Output yang Dihasilkan:
Halo, Budi! Saya sopir Anda.
Selamat datang, Siti!Mari kita telaah baris-barisnya:
- Baris 3-4 (
class Penyapa(Protocol)):Penyapahanya memuat deklarasidef sapa(self, nama: str) -> str: ...— tanda...menandai “ini spesifikasi, bukan implementasi”. - Baris 6 dan 10 (
class Sopir,class Pelayan): keduanya tidak mewarisiPenyapa— tidak ada hubungan pewarisan sama sekali. - Baris 15 (
tim: Penyapa): parametertimbertipe Protocol; pemanggil boleh mengirim object apa pun selama method yang dibutuhkan ada dan cocok bentuknya. - Baris 18-19:
SopirdanPelayanditerima karena keduanya memiliki methodsapadengan tanda tangan yang cocok — itulah seluruh bukti yang diminta checker.
Checker menolak object yang bentuknya tidak cocok, tanpa peduli asal-usul class-nya. Simpan sebagai kurir.py:
from typing import Protocol
class Penyapa(Protocol):
def sapa(self, nama: str) -> str: ...
class Kurir:
def antar(self, nama: str) -> str:
return f"Paket untuk {nama}!"
def layani(tim: Penyapa, nama: str) -> str:
return tim.sapa(nama)
print(layani(Kurir(), "Budi"))python3 -m mypy kurir.pyOutput yang Dihasilkan:
kurir.py:13: error: Argument 1 to "layani" has incompatible type "Kurir"; expected "Penyapa" [arg-type]
Found 1 error in 1 file (checked 1 source file)Kurir punya method antar, bukan sapa — bentuknya tidak cocok dengan kontrak Penyapa, sehingga mypy menolak pemanggilan tersebut.
runtime_checkable: Protocol di Sisi Runtime #
Secara bawaan, Protocol hanya hidup di dunia checker. Dekorator @runtime_checkable menambahkan kemampuan satu hal: isinstance() terhadap Protocol:
from typing import Protocol, runtime_checkable
@runtime_checkable
class Penyapa(Protocol):
def sapa(self, nama: str) -> str: ...
class Sopir:
def sapa(self, nama: str) -> str:
return f"Halo, {nama}!"
class Kunci:
pass
print(isinstance(Sopir(), Penyapa))
print(isinstance(Kunci(), Penyapa))Output yang Dihasilkan:
True
FalseObject Sopir cocok karena method sapa ada; object Kunci ditolak karena tidak punya method tersebut.
Protocol, ABC, atau Interface Biasa? #
Pilih berdasarkan siapa yang mengendalikan class penggunanya. Untuk kerangka class internal milik project sendiri, ABC tetap tepat — hubungan eksplisit memudahkan berbagi perilaku. Untuk titik perluasan yang diisi pihak luar (plugin, integrasi library, dependency injection), Protocol unggul: pengguna cukup menulis class dengan method yang cocok tanpa mengimpor satu pun symbol milik kita. Pemeriksaan isinstance penuh di runtime bukan bidang keduanya — untuk itu gunakan ABC.
Dengan Protocol, kita menutup rangkaian alat untuk menulis kontrak. Tinggal satu pola lagi: satu nama function dengan beberapa tanda tangan berbeda — tugas chapter Overload berikutnya.