Dekoratörler — bir fonksiyonu alıp, onun davranışını genişleten veya değiştiren yeni bir fonksiyon döndüren fonksiyonlardır. Genellikle günlüğe kaydetme, yetki kontrolü, önbellekleme, çalışma süresi ve diğerleri için kullanılır.
Dekoratörler, kapanışlar (closure) veya __call__ yöntemini uygulayan sınıflar aracılığıyla gerçekleştirilir. Klasik sözdizimi:
# Basit dekoratör def simple_decorator(func): def wrapper(*args, **kwargs): print("Fonksiyondan önce") result = func(*args, **kwargs) print("Fonksiyondan sonra") return result return wrapper @simple_decorator def my_func(): print("Ana fonksiyon") my_func()
Sonuç şöyle çalışacaktır:
Fonksiyondan önce
Ana fonksiyon
Fonksiyondan sonra
Ana fayda — tekrarlayan mantığı ana iş mantığının dışında kapsüllemektir.
İncelikler:
functools.wraps kullanılmadığında, orijinal fonksiyonun adı ve docstring'i kaybolur.Soru: "Eğer bir fonksiyonu dekoratörle süslersem ve sonra __name__ ile fonksiyonun adını almayı denersem ne görürüm ve orijinal adı nasıl korurum?"
Cevap:
Varsayılan olarak adı sarmalayıcının adı (genellikle wrapper) olarak değişecektir. Orijinal meta verileri korumak için functools.wraps kullanın:
import functools def dec(f): @functools.wraps(f) def wrapper(*args): return f(*args) return wrapper @dec def foo(): pass print(foo.__name__) # 'foo' döndürür, 'wrapper' değil
Hikaye
Büyük bir kaynak otomasyonunda, fonksiyonları dekoratörlerle sarmaladıktan sonra, test fonksiyonlarının isimleri aracılığıyla yansıma kullanan otomatik test sistemi bozuldu. Problem functools.wraps eksikliğiydi.
Hikaye
Günlük ekleyen bir dekoratör, *args, **kwargs kullanılmadığı için, farklı imzalı fonksiyonları desteklemiyordu. Bazı fonksiyonlar sadece Silent Fail ile bozuldu.
Hikaye
REST API'deki kimlik doğrulama projesinde, geliştirici parametrik bir dekoratör uyguladı ancak fonksiyonları doğru şekilde iç içe yerleştirmeyi unuttu (üç seviyeli iç içe yerine iki seviyeli iç içe oldu). Sonuç olarak, dekoratör parametreleri alamadı.