CodeBlanks Logo Icon CodeBlanks

Parametreli decorator

Parametreli decorator yazmayı öğrenirsin.

Parametreli decorator

Bir decorator, başka bir fonksiyonu saran ve davranışını değiştiren çağrılabilen bir nesnedir. Parametreli decorator ise, sarma işlemini yapılandıran ek argümanlar alır.

Önce dışta bir factory fonksiyonu tanımlanır: def repeat(n):. Bu fonksiyon, gerçek decorator'ü döndürür; decorator de sarmalanan fonksiyonu döndürür. Üç katmanlı yapı şöyledir:

def repeat(n):
    def deco(fn):
        def wrapper(*args):
            for _ in range(n):
                fn(*args)
        return wrapper
    return deco

Kullanımı @repeat(3) biçimindedir; çağrıdaki 3 argümanı factory'ye gider.

functools.wraps ile imza koruma

Bir decorator, sarmaladığı fonksiyonun adını, docstring'ini ve imzasını kaybeder; çünkü artık wrapper çağrılır. Bu durum hata ayıklamayı ve yardım çıktısını bozar.

Çözüm: functools.wraps(fn) decorator'ünü wrapper'ın üstüne koymak. Orijinal fonksiyonun meta verilerini wrapper'a kopyalar.

from functools import wraps

def repeat(n):
    def deco(fn):
        @wraps(fn)
        def wrapper(*args):
            ...
        return wrapper
    return deco

Böylece help(my_fn) hâlâ orijinal docstring'i gösterir.

Uygulama Parametreli @repeat decorator'ü yaz

Üç katmanlı bir parametreli decorator yaz. Factory repeat(n), decorator deco(fn) ve sarmalayan wrapper(*args) iç içe olsun. wrapper, fn(*args) çağrısını tam n kez yapsın. @wraps(fn) ile meta veriyi koru. @repeat(2) ile süslenmiş greet(name) fonksiyonu name değerini iki kez yazdırsın; en son greet("Ayşe") çağrısını yap.

Başlangıç kodu

main.py
from functools import wraps

# repeat(n) factory'si; içine deco ve wrapper tanımla
# wrapper'ı wraps decorator'ü ile süsle
# wrapper gövdesinde n kez orijinal fonksiyonu çağır

@repeat(2)
def greet(name):
    print(name)

greet("Ayşe")

Örnek çözüm

main.py
from functools import wraps

def repeat(n):
    def deco(fn):
        @wraps(fn)
        def wrapper(*args):
            for _ in range(n):
                fn(*args)
        return wrapper
    return deco

@repeat(2)
def greet(name):
    print(name)

greet("Ayşe")

Beklenen çıktı

Ayşe
Ayşe

Soru ve cevaplar

Dersin sorularını cevaplarıyla birlikte inceleyebilirsin. Kendini denemek istersen dersi interaktif olarak çöz.

1 Parametreli decorator'de @repeat(3) çağrısındaki 3 nereye gider?

  • Factory fonksiyonuna (repeat) Doğru cevap
  • Doğrudan sarmalanan fonksiyona
  • wrapper fonksiyonuna
  • deco fonksiyonuna

Açıklama: repeat(3) önce factory'yi çağırır; 3 factory'nin n parametresine bağlanır.

2 wraps decorator'ünü ekle

Soru
from functools import wraps

def repeat(n):
    def deco(fn):
        @____(fn)
        def wrapper(*args):
            for _ in range(n):
                fn(*args)
        return wrapper
    return deco
Cevap
from functools import wraps

def repeat(n):
    def deco(fn):
        @wraps(fn)
        def wrapper(*args):
            for _ in range(n):
                fn(*args)
        return wrapper
    return deco

Açıklama: @wraps(fn), orijinal fonksiyonun ad ve docstring'ini wrapper'a kopyalar.

3 Parametreli decorator katmanlarını eşleştir

Kavram Anlamı
repeat(n) En dış factory
deco(fn) Gerçek decorator
wrapper(*args) Sarmalayan fonksiyon
@wraps(fn) Meta veriyi korur

İleri seviye bölümündeki tüm dersler