2.23. Dekorator

Dekorator adalah potongan sintaks yang membungkus fungsi (atau metode) dalam fungsi lain. Pembungkus dapat menambahkan perilaku sebelum dan sesudah panggilan asli, mengganti nilai kembalian, atau melampirkan metadata. Bentuknya adalah:

@wrapper
def f():
    ...

Baris @wrapper setara dengan f = wrapper(f) -- fungsi f dibangun secara normal, kemudian diserahkan ke wrapper, dan hasilnya terikat kembali ke nama f.

A function entering a "wrapper" box on the left and emerging on the right as a decorated function.

Dekorator mengambil fungsi masuk dan mengembalikan fungsi baru.

2.23.1. Dekorator metode bawaan

Beberapa dekorator disertakan dengan Python dan digunakan di dalam badan kelas.

2.23.1.1. @property

Mengubah metode menjadi atribut terkomputasi. Pemanggil mengaksesnya seolah-olah itu adalah atribut biasa (tanpa tanda kurung), tetapi sebuah metode berjalan pada setiap pembacaan:

class Circle:
    def __init__(self, radius):
        self.radius = radius

    @property
    def area(self):
        return 3.14159 * self.radius * self.radius

c = Circle(5)
print(c.area)             # 78.53975  -- no parentheses

Gunakan ketika atribut yang terlihat sederhana memerlukan komputasi kecil di baliknya. Jika pekerjaan itu mahal, lebih baik gunakan metode biasa -- pemanggil tidak mengharapkan pembacaan atribut menjadi lambat.

2.23.1.2. @classmethod

Mendefinisikan metode yang menerima kelas sebagai argumen pertamanya alih-alih instans. Parameter pertama secara konvensional diberi nama cls:

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    @classmethod
    def origin(cls):
        return cls(0, 0)

p = Point.origin()

Metode kelas adalah cara standar untuk menyediakan konstruktor alternatif -- fungsi pabrik yang mengembalikan instans yang dibangun dengan cara non-default.

2.23.1.3. @staticmethod

Mendefinisikan metode yang tidak menerima instans maupun kelas -- itu hanyalah fungsi biasa yang berada di namespace kelas karena alasan organisasi:

class Temperature:
    @staticmethod
    def c_to_f(c):
        return c * 9 / 5 + 32

Temperature.c_to_f(100)   # 212.0

Gunakan dengan hemat; jika fungsi benar-benar tidak ada hubungannya dengan status kelas, fungsi biasa di tingkat modul biasanya lebih bersih.

2.23.2. Menulis dekorator kustom

Dekorator adalah fungsi yang mengambil fungsi dan mengembalikan fungsi. Bentuk minimumnya:

def log_calls(func):
    def wrapper(*args, **kwargs):
        print("calling", func.__name__)
        return func(*args, **kwargs)
    return wrapper

@log_calls
def add(a, b):
    return a + b

add(2, 3)

Output:

calling add

wrapper menutup func dan meneruskan semuanya ke sana. *args / **kwargs memungkinkannya bekerja pada fungsi apa pun, bukan hanya yang dua argumen. Pola ini adalah fondasi dekorator yang lebih rumit (pengaturan waktu, cache, coba-lagi-saat-gagal) tetapi intinya selalu sama: ambil fungsi masuk, kembalikan fungsi keluar.