ProgramlamaPython Geliştirici

Python dekoratörleri nedir, argümanlarla nasıl uygulanır, nerelerde kullanımı geçerlidir ve kendi argümanlı dekoratörlerinizi yazarken hangi nüanslara dikkat etmelisiniz?

Hintsage yapay zeka asistanı ile mülakatları geçin

Cevap

Soru Tarihi

Dekoratörler, Python'un en güçlü araçlarından biridir ve işlevlerin veya yöntemlerin davranışını değiştirmeye olanak tanır. Bazen sadece bir işlevi "sarmak" yerine, dekoratörü parametrelerle (argümanlarla) ayarlamak gerekir. Bu durumlar, günlük günlüğü, zaman kontrolleri, erişim kısıtlamaları vb. durumlarda ortaya çıkar.

Problem

Normal dekoratörler yalnızca sarmak gereken bir işlev alır. Dekoratöre parametreler iletildiğinde, sözdizimi daha karmaşık hale gelir ve bu sıklıkla hatalara yol açar, özellikle işlevlerin iç içe geçmesi ve *args/**kwargs ile geçiş yapılması durumunda.

Çözüm

Parametreli dekoratör, daha yüksek bir sıradaki fonksiyonla uygulanır: önce argümanlarla dış "dekoratör" fonksiyonu çağrılır, ardından bu fonksiyon dekoratörü oluşturup geri döner, ve dekoratör ise işlevi alır ve sarma işlemini gerçekleştirir:

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 greet(name): print(f"Hello, {name}!") greet("Python") # Çıktı: Hello, Python! (3 kez)

Anahtar özellikler:

  • Parametreli dekoratör her zaman üçlü iç içe fonksiyonlar ile gerçekleştirilir
  • Wrapper, sonucu döndürmeli ve *args/**kwargs'ı doğru şekilde geçiştirmelidir
  • Meta verileri korumak için functools.wraps'ı unutmayın

İnce Sorular.

Parametreli dekoratörü neden normal dekoratör gibi uygulayamıyorsunuz?

Eğer @decorator uygularsanız, Python işlevi dekoratöre argüman olarak geçirir. Parantez eklediğinizde (@decorator()), Python önce fonksiyonu çağırır ve sadece onun sonucu dekoratör olarak yorumlanır.

def deco(func): # normal dekoratör: @deco def deco_with_args(arg): # argümanlı dekoratör: @deco_with_args(arg)

Parametreli dekoratörler, parametresiz dekoratörlerden ne şekilde farklıdır?

Parametresiz dekoratörler bir işlev alır; argümanlı dekoratörler ise bir işlev değil, parametreler alır ve kendilerinden dekoratör döndürür.

functools.wraps'ı nasıl doğru kullanmalıyım ve neden?

functools.wraps(func) sarma işlemi içinde, orijinal işlevin adını, belgelendirme dizgisini ve diğer meta verileri korur, aksi takdirde bu bilgiler wrapper'da değiştirilir, bu da hata ayıklamayı ve intospeksiyonu zorlaştırır.

import functools def deco_with_args(arg): def decorator(func): @functools.wraps(func) def wrapper(*args, **kwargs): return func(*args, **kwargs) return wrapper return decorator

Tipik hatalar ve anti-deseni

  • Üç iç içe fonksiyon olma gereğini unutur, sadece iki (ya da tamamen bir) yaparlar, sonuç dekoratör olmaz
  • *args/**kwargs'ı wrapper'ın içine geçiştirmeyi unutur
  • functools.wraps yokluğunda fonksiyonun meta bilgisini kaybederler

Gerçek Hayat Örneği

Olumsuz Durum

Parametreleri dikkate almadan ya da yanlış iç içe fonksiyon sayısıyla dekoratör oluşturmuş:

def log(level): def wrapper(func): # hata — wrapper daha derin olmalı print(f"Log: {level}") func() # İşlev dekoratör olarak döndürülmez return wrapper @log("INFO") def action(): print("Work!")

Artılar:

  • Basit görünür

Eksiler:

  • Dekoratör çalışmaz, işlev dekorasyon sırasında çağrılır, action() çağrıldığında değil

Olumlu Durum

functools.wraps ve doğru iç içe fonksiyonlar kullanımı:

import functools def timer(units): def decorator(func): @functools.wraps(func) def wrapper(*args, **kwargs): import time start = time.time() result = func(*args, **kwargs) end = time.time() if units == 'ms': duration = (end - start) * 1000 else: duration = end - start print(f"Duration: {duration:.4f} {units}") return result return wrapper return decorator @timer('ms') def op(): sum(range(1000)) op()

Artılar:

  • Doğru yapı, genişletilmesi kolay, temiz günlükler

Eksiler:

  • Özellikle yeni başlayanlar için okunması daha zor