ProgramlamaPython Backend разработчик

Python'da işlevler için dekoratörler nedir, tarihi nedir ve modern programlamada neden kullanılırlar?

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

Cevap

Tarihçe

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ı.

Sorun

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.

Çözüm

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:

  • Kodun yeniden kullanılmasına olanak tanır (Kuru-Prensibi);
  • İşlevler, yöntemler, sınıflar için kullanılabilir;
  • Günlüğe kaydetme, önbellek, erişim, profil oluşturma gibi çapraz işlevsellik görevlerini merkezi olarak entegre etmeye olanak tanır;

Kandırma Soruları.

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

Yaygın Hatalar ve Anti-Desenler

  • functools.wraps'ı göz ardı etmek, orijinal işlev hakkında meta bilgiyi kaybettirir;
  • Dekoratörün mantığı istisnaları dikkate almaz, hata içinden yakalanamaz ve işlenemez;
  • Birden fazla dekoratörün etkisinin belirsiz olması

Hayattan Bir Örnek

Olumsuz Durum

Zaman kaydının 10 işlev için manuel olarak, kopyalayarak eklenmesi.

Artıları:

  • Mantık net, kod yan yana, hatayı bulmak kolay.

Eksileri:

  • Bakımı zor — davranışı değiştirmek gerektiğinde onlarca yeri değiştirmek gerekecek.
  • Kod tekrar ediyor, Kuru'yu ihlal ediyor.

Olumlu Durum

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ı:

  • Değişiklikler merkezi olarak yapılır;
  • Kod daha kısa ve okunabilir.

Eksileri:

  • functools.wraps olmadan imza bilgisi kaybedilebilir, dikkat edilmezse;
  • Yeni başlayanların dekoratörlerin çalışma mekanizmasını anlaması daha zor.