Traffine I/O

Bahasa Indonesia

2023-03-31

Protokol dalam Python

Apa itu Protokol

Protokol adalah fitur yang kuat dari sistem tipe Python yang memungkinkan hint tipe yang lebih fleksibel dan ekspresif. Protokol adalah bagian dari modul typing, yang digunakan untuk memberikan anotasi tipe dalam kode Python. Protokol dibangun berdasarkan konsep tipe struktural, berfokus pada perilaku atau struktur tipe, bukan pada hierarki pewarisan eksplisitnya. Ini memungkinkan Anda untuk menentukan antarmuka untuk kelas Anda dan membuat kode yang lebih kuat dan mudah dipelihara.

Menggunakan Protokol di Python dapat sangat meningkatkan keterbacaan dan keberlanjutan kode Anda. Dengan memberikan informasi eksplisit tentang jenis input dan output yang diharapkan dari fungsi dan metode, Anda membuat kode Anda lebih mudah dipahami oleh pengembang lain dan lebih mudah didokumentasikan. Selain itu, informasi ini dapat dimanfaatkan oleh periksa tipe statis seperti Mypy untuk menangkap kesalahan dan ketidakcocokan tipe potensial sebelum menyebabkan kesalahan waktu eksekusi.

Cara Menggunakan Protokol

Untuk bekerja dengan Protokol, Anda pertama-tama perlu memahami kelas typing.Protocol. Kelas typing.Protocol adalah metakelas yang digunakan untuk menentukan kelas protokol baru. Untuk membuat protokol kustom, Anda perlu mewarisi kelas typing.Protocol dan menentukan atribut dan metode yang diperlukan dalam kelas baru.

Protokol kustom dibuat dengan mendefinisikan kelas baru yang mewarisi dari typing.Protocol. Kelas ini harus mencakup metode dan properti yang diinginkan, yang kemudian digunakan untuk mengekspresikan perilaku yang diharapkan dari tipe apa pun yang mengimplementasikan protokol ini.

Sebagai contoh, untuk menentukan protokol kustom untuk titik dua dimensi, Anda dapat membuat kelas baru yang disebut Point2D yang mewarisi dari typing.Protocol:

python
from typing import Protocol

class Point2D(Protocol):
    x: float
    y: float

    def distance_to_origin(self) -> float:
        ...

Dalam contoh ini, protokol Point2D menentukan bahwa setiap tipe yang mengimplementasikannya harus memiliki properti x dan y dengan tipe float, dan sebuah metode yang disebut distance_to_origin yang mengembalikan float. Ketika Anda menggunakan protokol Point2D sebagai hint tipe dalam kode Anda, Anda menunjukkan bahwa tipe yang diharapkan harus memiliki properti dan metode ini, terlepas dari hierarki pewarisannya yang sebenarnya.

Dengan membuat dan menggunakan Protokol kustom, Anda dapat menulis hint tipe yang lebih ekspresif dan fleksibel dalam kode Python Anda, yang pada akhirnya akan mengarah pada proyek yang lebih kuat dan mudah dipelihara.

Perbandingan dengan Kelas Basis Abstrak (abc)

Meskipun keduanya, typing.Protocol dan kelas basis abstrak (ABC), membantu menentukan antarmuka untuk kelas Python, mereka berbeda dalam beberapa aspek utama:

typing.Protocol berfokus pada subtyping struktural, sedangkan ABC menekankan subtyping nominal. Ini berarti bahwa protokol berfokus pada struktur dan perilaku tipe, sedangkan ABC didasarkan pada hubungan pewarisan eksplisit.

Protokol lebih fleksibel daripada ABC, karena mereka tidak memaksa implementasi. Sebuah kelas dapat sesuai dengan protokol tanpa secara eksplisit mewarisi dari protokol tersebut, selama ia memiliki atribut dan metode yang diperlukan.

ABC dapat memaksa implementasi metode abstraknya pada waktu eksekusi, sedangkan protokol tidak memiliki kemampuan ini secara default. Namun, Anda dapat menggunakan decorator runtime_checkable untuk melakukan pemeriksaan waktu eksekusi dengan protokol.

Kapan Menggunakan Protokol vs Kelas Basis Abstrak

typing.Protocol umumnya lebih disukai ketika Anda ingin berfokus pada struktur dan perilaku tipe, tanpa memaksa hubungan pewarisan. Mereka sangat berguna untuk membuat protokol adapter untuk pustaka pihak ketiga, menentukan objek seperti file, dan menciptakan antarmuka iterable dan iterator kustom.

ABC, di sisi lain, lebih cocok untuk kasus di mana Anda ingin memaksa implementasi metode tertentu pada waktu eksekusi dan menetapkan hierarki pewarisan eksplisit.

Contoh Scikit-learn dengan typing.Protocol

Scikit-learn menyediakan berbagai jenis estimator machine learning. Anda dapat menentukan protokol estimator kustom yang menjabarkan metode yang dibutuhkan untuk estimator yang sesuai dengan Scikit-learn:

python
from typing import Any, Protocol
import numpy as np

class SklearnEstimator(Protocol):
    def fit(self, X: np.ndarray, y: np.ndarray, **kwargs: Any) -> "SklearnEstimator":
        ...

    def predict(self, X: np.ndarray) -> np.ndarray:
        ...

    def score(self, X: np.ndarray, y: np.ndarray) -> float:
        ...

Dengan protokol estimator kustom yang disiapkan, Anda dapat mengimplementasikan estimator baru yang mengikuti protokol:

python
from sklearn.base import BaseEstimator, ClassifierMixin
import numpy as np

class CustomEstimator(BaseEstimator, ClassifierMixin):
    def fit(self, X: np.ndarray, y: np.ndarray) -> "CustomEstimator":
        # Implementation of the fit method
        ...

    def predict(self, X: np.ndarray) -> np.ndarray:
        # Implementation of the predict method
        ...

    def score(self, X: np.ndarray, y: np.ndarray) -> float:
        # Implementation of the score method
        ...

Dengan protokol estimator kustom SklearnEstimator, Anda dapat membuat fungsi yang bekerja dengan estimator yang sesuai dengan Scikit-learn:

python
from sklearn.model_selection import cross_val_score
from typing import List

def evaluate_estimators(estimators: List[SklearnEstimator], X: np.ndarray, y: np.ndarray) -> None:
    for estimator in estimators:
        scores = cross_val_score(estimator, X, y, cv=5)

    print(f"{estimator.__class__.__name__}:")
    print(f"  Mean cross-validation score: {scores.mean():.3f}")
    print(f"  Standard deviation: {scores.std():.3f}\n")

In this example, the evaluate_estimators function accepts a list of estimators that conform to the SklearnEstimator protocol, and it uses the cross_val_score function from scikit-learn to evaluate each estimator's performance.

By leveraging the custom SklearnEstimator protocol, you can ensure that any estimator passed to the evaluate_estimators function has the required fit, predict, and score methods, thus making your code more robust and maintainable.

Referensi

https://peps.python.org/pep-0544/
https://mypy.readthedocs.io/en/stable/protocols.html

Ryusei Kakujo

researchgatelinkedingithub

Focusing on data science for mobility

Bench Press 100kg!