Dekoratörler Python'da 2.4 sürümüyle birlikte üst düzey işlevlerle (başka işlevleri alan veya döndüren) çalışmayı kolaylaştırmak için sözdizimsel şeker olarak ortaya çıktı. İşlevlerin işlevselliğini genişletme yaklaşımlarının evrimi, @decorator ile ifadeleri özlü ve ifade edici hale getiren bir formatla sonuçlandı.
Büyük projelerde, genellikle işlevleri ek bir mantıkla modifiye etmek veya sarmak gerekir: günlüğe kaydetme, erişim kontrolü, önbellekleme, çalışma süresini ölçme. Dekoratörler olmadan, sarıcı işlevleri manuel olarak çağırmak gerekiyordu, bu da kodun şişmesine neden oluyordu.
Dekoratörler, yineleyen yönleri ayrı sarıcılara ayırarak kodun okunabilirliğini ve yeniden kullanılabilirliğini artırır. @decorator ile işlevlere ve yöntemlere fonksiyonalite eklemek zarif bir şekilde mümkündür:
Kod Örneği:
import time def timing_decorator(func): def wrapper(*args, **kwargs): start = time.time() result = func(*args, **kwargs) print(f'Geçen süre: {time.time() - start:.3f}s') return result return wrapper @timing_decorator def slow_function(): time.sleep(0.5) slow_function() # Çalışma süresini yazdırır
Ana özellikler:
Dekoratörler, sarılan işlevin imzasını değiştirebilir mi?
Sıklıkla, dekoratörün işlevin imzasını değiştirmediği yanlış anlaşılır. Aslında functools.wraps modülü kullanılmadan, meta bilgi kaybolur ve bu da otomatik belgelerde veya introspection'da beklenmedik hatalara yol açabilir.
Kod Örneği:
from functools import wraps def decorator(func): @wraps(func) def wrapper(*args): return func(*args) return wrapper
Dekoratörler parametre alabilir mi?
Sıklıkla hayır denir. Aslında, bir dekoratörü döndüren ek bir iç içe fonksiyon ile parametreli bir dekoratör oluşturmak mümkündür.
Kod Örneği:
def repeat(n): def decorator(func): def wrapper(*args, **kwargs): result = None for _ in range(n): result = func(*args, **kwargs) return result return wrapper return decorator @repeat(3) def hello(): print("Merhaba!")
Bir işleve birden fazla dekoratör uygulanabilir mi? Uygulama sırası ne olur?
Sıklıkla, sıranın önemli olmadığı veya dekoratörlerin kodda yerleştirildiği sırayla eşleştiği düşünülür. Aslında, önce en alt dekoratör uygulanır, ardından bir sonraki ve yukarı doğru devam edilir.
Kod Örneği:
def dec1(f): def wrapper(*a, **k): print("dec1") return f(*a, **k) return wrapper def dec2(f): def wrapper(*a, **k): print("dec2") return f(*a, **k) return wrapper @dec1 @dec2 def f(): print("kütle") f() # dec1, dec2, kütle
Zaman kaydının 10 işlev için manuel olarak, kopyalayarak eklenmesi.
Artıları:
Eksileri:
Tüm zamanlama mantığı bir dekoratöre çıkarıldı, bu metriğe ihtiyaç duyan tüm işlevler @timing_decorator dekoratörüyle sarıldı.
Artıları:
Eksileri:
functools.wraps olmadan imza bilgisi kaybedilebilir, dikkat edilmezse;