9 Dekorator Built-In Python Yang Mengoptimalkan Kode Anda Secara Signifikan
"Bentuk sederhana lebih baik daripada yang kompleks."
Fitur Python terbaik yang mengaplikasikan filosofi dari "zen of Python" ini adalah dekorator.
Dekorator bisa membantu Anda menulis code yang lebih sedikit dan lebih simpel untuk menerapkan logika kompleks dan menggunakannya kembali dimanapun.
Lebih penting lagi, ada beberapa dekorator Python bawaan yang menakjubkan yang membuat hidup kita lebih mudah, karena kita hanya bisa menggunakan satu baris code untuk menambahkan fungsionalitas sulit ke fungsi atau kelas yang ada.
Berbicara itu murah. Mari kita lihat 9 dekorator pilihan saya yang akan menunjukkan betapa elegannya Python.
1. @lru_cache: Percepat Program Anda dengan Caching
Cara termudah untuk mempercepat fungsi Python Anda dengan trik caching adalah dengan menggunakan dekorator @lru_cache
.
Dekorator ini dapat digunakan untuk meng-cache hasil dari suatu fungsi, sehingga panggilan selanjutnya ke fungsi dengan argumen yang sama tidak akan dijalankan lagi.
Ini sangat membantu untuk fungsi yang mahal secara komputasi atau yang sering dipanggil dengan argumen yang sama.
Mari kita lihat contoh intuitif:
import time
def fibonacci(n):
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
start_time = time.perf_counter()
print(fibonacci(30))
end_time = time.perf_counter()
print(f"The execution time: {end_time - start_time:.8f} seconds")
# The execution time: 0.18129450 seconds
Program di atas menghitung angka Fibonacci ke-N dengan fungsi Python. Ini memakan waktu karena ketika Anda menghitung fibonacci(30)
, banyak angka Fibonacci sebelumnya akan dihitung berkali-kali selama proses rekursi.
Sekarang, mari percepat dengan dekorator @lru_cache
:
from functools import lru_cache
import time
@lru_cache(maxsize=None)
def fibonacci(n):
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
start_time = time.perf_counter()
print(fibonacci(30))
end_time = time.perf_counter()
print(f"The execution time: {end_time - start_time:.8f} seconds")
# The execution time: 0.00002990 seconds
Seperti yang ditunjukkan kode di atas, setelah menggunakan dekorator @lru_cache
, kita bisa mendapatkan hasil yang sama dalam 0,00002990
detik, yang lebih cepat dari 0,18129450
detik sebelumnya.
Dekorator @lru_cache
memiliki parameter ukuran maksimal yang menentukan jumlah maksimum hasil yang akan disimpan dalam cache. Saat cache penuh dan hasil baru perlu disimpan, hasil yang terakhir digunakan dikeluarkan dari cache untuk memberi ruang bagi yang baru. Ini disebut strategi yang paling baru digunakan (LRU).
Secara default, ukuran maksimum disetel ke 128
. Jika disetel ke None
(Tidak ada), sebagai contoh kami, fitur LRU dinonaktifkan dan cache dapat bertambah tanpa terikat.
2. @total_ordering: Dekorator Kelas yang Mengisi Metode Pengurutan yang Hilang
Dekorator @total_ordering
dari modul functools
digunakan untuk menghasilkan metode perbandingan yang hilang untuk kelas Python berdasarkan yang ditentukan.
Berikut contohnya:
from functools import total_ordering
@total_ordering
class Student:
def __init__(self, name, grade):
self.name = name
self.grade = grade
def __eq__(self, other):
return self.grade == other.grade
def __lt__(self, other):
return self.grade < other.grade
student1 = Student("Alice", 85)
student2 = Student("Bob", 75)
student3 = Student("Charlie", 85)
print(student1 < student2) # False
print(student1 > student2) # True
print(student1 == student3) # True
print(student1 <= student3) # True
print(student3 >= student2) # True
Seperti yang diilustrasikan kode di atas, tidak ada definisi untuk metode __ge__
, __gt__
, dan __le__
di kelas Student
. Namun, terima kasih kepada dekorator @total_ordering
, hasil perbandingan kami antara instance yang berbeda semuanya benar.
Manfaat dekorator ini jelas:
- Itu dapat membuat kode Anda lebih bersih dan menghemat waktu Anda. Karena Anda tidak perlu menulis semua metode perbandingan.
-
Beberapa kelas lama mungkin tidak cukup mendefinisikan metode perbandingan. Lebih aman menambahkan dekorator
@total_ordering
ke dalamnya untuk penggunaan lebih lanjut.
3. @contextmanager: Membuat Pengelola Konteks Khusus
Python memiliki mekanisme pengelola konteks untuk membantu Anda mengelola sumber daya dengan benar.
Sebagian besar, kita hanya perlu menggunakan pernyataan with
:
with open("test.txt",'w') as f:
f.write("Yang is writing!")
Seperti yang ditunjukkan kode di atas, kita dapat membuka file menggunakan pernyataan with
sehingga akan ditutup secara otomatis setelah ditulis. Kita tidak perlu memanggil fungsi f.close()
secara eksplisit untuk menutup file.
Terkadang, kita perlu menentukan pengelola konteks khusus untuk beberapa persyaratan khusus. Dalam hal ini, dekorator @contextmanager adalah teman kita.
Misalnya, kode berikut mengimplementasikan manajer konteks kustom sederhana yang dapat mencetak informasi terkait saat file dibuka atau ditutup.
from contextlib import contextmanager
@contextmanager
def file_manager(filename, mode):
print("The file is opening...")
file = open(filename,mode)
yield file
print("The file is closing...")
file.close()
with file_manager('test.txt', 'w') as f:
f.write('Yang is writing!')
# The file is opening...
# The file is closing...
4. @property: Menyiapkan Getter dan Setter untuk Kelas Python
Getter dan setter adalah konsep penting dalam pemrograman berorientasi objek (OOP).
Untuk setiap variabel instan kelas, metode pengambil mengembalikan nilainya sementara metode penyetel menetapkan atau memperbarui nilainya. Mengingat hal ini, getter dan setter masing-masing juga dikenal sebagai pengakses dan mutator.
Mereka digunakan untuk melindungi data Anda agar tidak diakses atau dimodifikasi secara langsung dan tidak terduga.
Bahasa OOP yang berbeda memiliki mekanisme yang berbeda untuk mendefinisikan getter dan setter. Di Python, kita cukup menggunakan dekorator @property
.
class Student:
def __init__(self):
self._score = 0
@property
def score(self):
return self._score
@score.setter
def score(self, s):
if 0 <= s <= 100:
self._score = s
else:
raise ValueError('The score must be between 0 ~ 100!')
Yang = Student()
Yang.score=99
print(Yang.score)
# 99
Yang.score = 999
# ValueError: The score must be between 0 ~ 100!
Seperti yang ditunjukkan contoh di atas, variabel skor tidak dapat ditetapkan sebagai 999, yang merupakan angka yang tidak berarti. Karena kami membatasi rentang yang dapat diterima di dalam fungsi setter menggunakan dekorator @property
.
Tanpa diragukan lagi, menambahkan penyetel ini dapat berhasil menghindari bug atau hasil yang tidak terduga.
5. @cached_property: Cache Hasil Metode sebagai Atribut
Python 3.8 memperkenalkan dekorator kuat baru ke modul functool
— @cached_property
. Itu dapat mengubah metode kelas menjadi properti yang nilainya dihitung sekali dan kemudian di-cache sebagai atribut normal selama masa pakai instance.
Ini contohnya:
from functools import cached_property
class Circle:
def __init__(self, radius):
self.radius = radius
@cached_property
def area(self):
return 3.14 * self.radius ** 2
circle = Circle(10)
print(circle.area)
# prints 314.0
print(circle.area)
# returns the cached result (314.0) directly
Pada kode di atas, kita mendekorasi metode area
melalui @cached_property
. Jadi tidak ada perhitungan berulang untuk circle.area
dari instance yang sama dan tidak berubah.
6. @classmethod: Menentukan Metode Kelas di Kelas Python
Di dalam kelas Python, ada 3 kemungkinan jenis metode:
-
Metode Instance: metode yang terikat pada sebuah instance. Mereka dapat mengakses dan memodifikasi data instance. Metode instance dipanggil pada instance kelas, dan dapat mengakses data instance melalui parameter
self
. -
Metode kelas: metode yang terikat ke kelas. Mereka tidak dapat mengubah data instance. Metode kelas dipanggil pada kelas itu sendiri, dan ia menerima kelas sebagai parameter pertama, yang biasanya bernama
cls
. - Metode statis: metode yang tidak terikat pada instance atau kelas.
Metode instance dapat didefinisikan sebagai fungsi Python normal selama parameter pertamanya adalah self
. Namun, untuk mendefinisikan metode kelas, kita perlu menggunakan dekorator @classmethod
.
Untuk mendemonstrasikan, contoh berikut mendefinisikan metode kelas yang dapat digunakan untuk mendapatkan instance Circle
melalui diameter:
class Circle:
def __init__(self, radius):
self.radius = radius
@classmethod
def from_diameter(cls, diameter):
return cls(diameter / 2)
@property
def diameter(self):
return self.radius * 2
@diameter.setter
def diameter(self, diameter):
self.radius = diameter / 2
c = Circle.from_diameter(8)
print(c.radius) # 4.0
print(c.diameter) # 8.0
7. @staticmethod: Menentukan Metode Statis di Kelas Python
Seperti disebutkan, metode statis tidak terikat pada instance atau kelas. Mereka termasuk dalam kelas hanya karena secara logis mereka termasuk di sana.
Metode statis umumnya digunakan dalam kelas utilitas yang melakukan sekelompok tugas terkait, seperti perhitungan matematis. Dengan mengatur fungsi terkait ke dalam metode statis di dalam kelas, kode kita akan menjadi lebih teratur dan lebih mudah dipahami.
Untuk mendefinisikan metode statis, kita hanya perlu menggunakan dekorator @staticmethod. Mari kita lihat contohnya:
class Student:
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
self.nickname = None
def set_nickname(self, name):
self.nickname = name
@staticmethod
def suitable_age(age):
return 6 <= age <= 70
print(Student.suitable_age(99)) # False
print(Student.suitable_age(27)) # True
print(Student('yang', 'zhou').suitable_age(27)) # True
8. @dataclass: Menentukan Kelas Khusus Dengan Kode Lebih Sedikit
Dekorator @dataclass
(diperkenalkan dengan Python 3.7) dapat secara otomatis menghasilkan beberapa metode khusus untuk sebuah kelas, seperti __init__
, __repr__
, __eq__
, __lt__
, dan seterusnya.
Oleh karena itu, ini dapat menghemat banyak waktu kita untuk menulis metode dasar ini. Jika kelas terutama digunakan untuk menyimpan data, dekorator @dataclass
adalah teman terbaik kita.
Untuk mendemonstrasikan, contoh berikut hanya mendefinisikan dua bidang data dari kelas bernama Point
. Berkat dekorator @dataclass
, cukup untuk digunakan:
from dataclasses import dataclass
@dataclass
class Point:
x: float
y: float
point = Point(1.0, 2.0)
print(point)
# Point(x=1.0, y=2.0)
9. @atexit.register: Daftarkan Fungsi yang Akan Dijalankan Setelah Penghentian Program Normal
Dekorator @register dari modul atexit dapat memungkinkan kita menjalankan fungsi saat juru bahasa Python keluar.
Dekorator ini sangat berguna untuk melakukan tugas akhir, seperti melepaskan sumber daya atau sekadar mengucapkan selamat tinggal!
Ini contohnya:
import atexit
@atexit.register
def goodbye():
print("Bye bye!")
print("Hello Yang!")
Outputnya adalah:
Hello Yang!
Bye bye!
Seperti yang ditunjukkan contoh, karena penggunaan dekorator @register, terminal mencetak "Bye bye!" bahkan jika kami tidak memanggil fungsi selamat tinggal secara eksplisit.
Terima kasih sudah membaca ❤