Python Decorator Parametreleri Rehberi

Yönetici

Python'da dekoratörler, fonksiyonların veya metotların davranışlarını değiştirmek için güçlü bir araçtır. Dekoratörlerin parametre alabilmesi, bu yapıyı daha esnek ve yeniden kullanılabilir hale getirir. Bu rehberde, Python dekoratörlerinin parametrelerle nasıl çalıştığını, nasıl oluşturulduğunu ve pratik kullanım örneklerini ele alacağız.

Dekoratör Nedir?​

Dekoratör, bir fonksiyonu veya metodu saran ve ona ek davranışlar ekleyen bir callable (çağrılabilir) nesnedir. Python'da dekoratörler genellikle @ sembolü ile tanımlanır ve fonksiyonların üzerine yerleştirilir. Parametreli dekoratörler, dekoratörün kendi argümanlarını almasına olanak tanır, böylece daha özelleştirilmiş davranışlar sağlanabilir.

Parametreli Dekoratörlerin Yapısı​

Parametreli bir dekoratör oluşturmak için üç katmanlı bir yapı kullanılır:
  1. En dış katman (decorator factory): Dekoratörün parametrelerini alır ve bir dekoratör döndürür.
  2. Dekoratör katmanı: Dekore edilecek fonksiyonu alır ve bir wrapper fonksiyon döndürür.
  3. Wrapper katmanı: Orijinal fonksiyonun çağrısını yönetir ve ek davranışları uygular.
Aşağıda basit bir parametreli dekoratör örneği verilmiştir:

Kod:
def tekrar_sayisi(sayi):
    def dekorator(fonksiyon):
        def wrapper(*args, **kwargs):
            for _ in range(sayi):
                fonksiyon(*args, **kwargs)
        return wrapper
    return dekorator

@tekrar_sayisi(3)
def selam_ver(isim):
    print(f"Merhaba, {isim}!")

selam_ver("Ali")

Çıktı:

Kod:
Merhaba, Ali!
Merhaba, Ali!
Merhaba, Ali!

Bu örnekte:
  • tekrar_sayisi dekoratör fabrikası, sayi parametresini alır.
  • dekorator fonksiyonu, dekore edilecek fonksiyonu (selam_ver) alır.
  • wrapper fonksiyonu, orijinal fonksiyonu belirtilen sayıda (sayi) çağırır.

Parametreli Dekoratörlerin Avantajları​

  • Esneklik: Dekoratörün davranışını parametrelerle özelleştirebilirsiniz.
  • Yeniden Kullanılabilirlik: Aynı dekoratörü farklı parametrelerle birden fazla fonksiyonda kullanabilirsiniz.
  • Kod Tekrarını Azaltma: Ortak davranışları merkezi bir şekilde tanımlayabilirsiniz.

Pratik Örnek: Yetki Kontrolü Dekoratörü​

Aşağıda, bir kullanıcının belirli bir rolü olup olmadığını kontrol eden bir parametreli dekoratör örneği verilmiştir:

Kod:
def yetki_kontrol(rol):
    def dekorator(fonksiyon):
        def wrapper(kullanici, *args, **kwargs):
            if kullanici.get('rol') == rol:
                return fonksiyon(kullanici, *args, **kwargs)
            else:
                raise PermissionError(f"Yetkisiz erişim: {rol} rolü gerekli.")
        return wrapper
    return dekorator

@yetki_kontrol("admin")
def gizli_veri_goster(kullanici):
    return "Bu gizli bir veridir!"

# Test
kullanici1 = {"isim": "Ali", "rol": "admin"}
kullanici2 = {"isim": "Veli", "rol": "user"}

print(gizli_veri_goster(kullanici1))  # Çıktı: Bu gizli bir veridir!
try:
    print(gizli_veri_goster(kullanici2))
except PermissionError as e:
    print(e)  # Çıktı: Yetkisiz erişim: admin rolü gerekli.

Bu dekoratör, yalnızca belirli bir role sahip kullanıcıların fonksiyonu çalıştırmasına izin verir.

İleri Düzey: Fonksiyon Meta Verilerini Koruma​

Dekoratörler, orijinal fonksiyonun meta verilerini (örneğin __name__, __doc__) kaybedebilir. Bunu önlemek için functools.wraps kullanılabilir:

Kod:
from functools import wraps

def log_kaydi(seviye):
    def dekorator(fonksiyon):
        @wraps(fonksiyon)
        def wrapper(*args, **kwargs):
            print(f"{seviye}: {fonksiyon.__name__} çağrıldı.")
            return fonksiyon(*args, **kwargs)
        return wrapper
    return dekorator

@log_kaydi("INFO")
def topla(a, b):
    """İki sayıyı toplar."""
    return a + b

print(topla(3, 5))  # Çıktı: INFO: topla çağrıldı. \n 8
print(topla.__name__)  # Çıktı: topla
print(topla.__doc__)   # Çıktı: İki sayıyı toplar.
@wraps(fonksiyon) sayesinde, orijinal fonksiyonun meta verileri korunur.

FAQs​

1. Parametreli dekoratör ile parametresiz dekoratör arasındaki fark nedir?

Parametreli dekoratörler, dekoratörün kendi argümanlarını almasını sağlar ve bu argümanlar dekoratörün davranışını özelleştirir. Parametresiz dekoratörler ise sabit bir davranış uygular.

2. Birden fazla parametre alan dekoratör nasıl yazılır?

Dekoratör fabrikası fonksiyonuna istediğiniz sayıda parametre tanımlayabilirsiniz. Örneğin:

Kod:
def log_kaydi(seviye, dosya):
    def dekorator(fonksiyon):
        def wrapper(*args, **kwargs):
            with open(dosya, 'a') as f:
                f.write(f"{seviye}: {fonksiyon.__name__} çağrıldı.\n")
            return fonksiyon(*args, **kwargs)
        return wrapper
    return dekorator

3. Parametreli dekoratörleri sınıflarda kullanabilir miyim?

Evet, sınıf metotlarını dekore etmek için parametreli dekoratörler kullanılabilir. Ancak, metotların self parametresini doğru şekilde işlediğinizden emin olun.

4. Dekoratörlerin performansa etkisi nedir?

Dekoratörler, her fonksiyon çağrısında ek bir katman oluşturur, bu nedenle mikro düzeyde performans etkisi olabilir. Ancak, çoğu uygulamada bu etki ihmal edilebilir düzeydedir.

5. Birden fazla dekoratörü aynı fonksiyonda kullanabilir miyim?

Evet, birden fazla dekoratör üst üste kullanılabilir. Dekoratörler, en üsttekinden en alttakine doğru sırayla uygulanır.

Sonuç​

Parametreli dekoratörler, Python'da kodunuzu daha modüler ve esnek hale getirmenin güçlü bir yoludur. Yetki kontrolü, loglama, tekrarlı çalıştırma gibi birçok senaryoda kullanılabilirler. functools.wraps gibi araçlarla daha sağlam dekoratörler yazabilir ve meta verileri koruyabilirsiniz. Bu rehberdeki örnekleri kullanarak kendi parametreli dekoratörlerinizi oluşturmaya başlayabilirsiniz!
 
Üst