Python, dinamik yapısı sayesinde kodların çalışma zamanında değiştirilmesine veya yeni işlevlerin eklenmesine olanak tanır. Bu özellikler, metaprogramlama ve decorator kullanımı ile daha güçlü ve esnek bir hale gelir. Bu makalede, metaprogramlamayı derinlemesine inceleyecek, decoratorların çalışma mantığını ve pratik kullanım alanlarını detaylı bir şekilde açıklayacağız.
Metaprogramlama Nedir?
Metaprogramlama, programların kendileri hakkında bilgi almasını, kendilerini analiz etmesini veya dinamik olarak değiştirmesini sağlayan bir programlama tekniğidir. Python, dinamik bir dil olduğundan, çalışma zamanında kod yapısını değiştirme yeteneğine sahiptir.
Python’da Metaprogramlama Araçları
1. type()
Fonksiyonu ile Dinamik Sınıf Yaratımı
Python’da tüm sınıflar aslında type
metaklası tarafından oluşturulur. Bu nedenle, type()
fonksiyonunu kullanarak dinamik olarak yeni sınıflar oluşturabiliriz.
Örnek:
# Yeni bir sınıf oluşturma YeniSınıf = type('YeniSınıf', (object,), {'merhaba': lambda self: "Merhaba Dünya!"}) # Sınıftan nesne yaratma nesne = YeniSınıf() print(nesne.merhaba()) # Çıktı: Merhaba Dünya!
Bu örnekte, YeniSınıf
adında bir sınıf yaratılıyor. Bu sınıfın merhaba()
isminde bir metodu var ve dinamik olarak tanımlanıyor.
2. getattr()
, setattr()
, hasattr()
, delattr()
Fonksiyonları
Python’da metaprogramlamayı mümkün kılan en önemli işlevlerden bazılarıdır.
Örnek:
class Araba: marka = "BMW" araba = Araba() # Özelliğin olup olmadığını kontrol etme print(hasattr(araba, 'marka')) # Çıktı: True # Özelliğe erişim print(getattr(araba, 'marka')) # Çıktı: BMW # Özellik ekleme veya değiştirme setattr(araba, 'model', 'M3') print(araba.model) # Çıktı: M3 # Özelliği silme delattr(araba, 'model')
Bu işlevler sayesinde Python’da dinamik olarak sınıfların ve nesnelerin özellikleri üzerinde işlem yapılabilir.
3. __call__()
Metodu
Python’da bir nesnenin çağrılabilir olması için __call__()
metodunun tanımlanması gerekir. Bu özellik, dekoratörlerin temelini oluşturur.
Örnek:
class ÇağrılabilirSınıf: def __call__(self): print("Nesne çağrıldı!") nesne = ÇağrılabilirSınıf() nesne() # Çıktı: Nesne çağrıldı!
Decorator (Dekoratör) Nedir?
Dekoratörler, Python fonksiyonlarına veya sınıflarına dinamik olarak yeni işlevsellikler eklemeye yarayan özel fonksiyonlardır.
Dekoratörlerin temel amacı, bir fonksiyonun davranışını değiştirmek veya geliştirmektir.
Python’da Dekoratör Kullanımı
Fonksiyon Dekoratörleri
Bir fonksiyonu başka bir fonksiyonla sarmalamak için kullanılır.
Örnek:
def dekoratör(fonksiyon): def sarmal(): print("Fonksiyon çağrılmadan önceki işlem.") fonksiyon() print("Fonksiyon çağrıldıktan sonraki işlem.") return sarmal @dekoratör def merhaba(): print("Merhaba Dünya!") merhaba()
Çıktı:
Fonksiyon çağrılmadan önceki işlem. Merhaba Dünya! Fonksiyon çağrıldıktan sonraki işlem.
Parametre Alan Dekoratörler
Dekoratörlerin parametre alarak daha esnek kullanımı mümkündür.
Örnek:
def tekrar(sayı): def dekoratör(fonksiyon): def sarmal(): for _ in range(sayı): fonksiyon() return sarmal return dekoratör @tekrar(3) def selamla(): print("Merhaba!") selamla()
Çıktı:
Merhaba! Merhaba! Merhaba!
Sınıf Dekoratörleri
Fonksiyonlar yerine sınıfları sarmalamak da mümkündür.
Örnek:
class Zamanlayıcı: def __init__(self, fonksiyon): self.fonksiyon = fonksiyon def __call__(self, *args, **kwargs): import time başlama = time.time() sonuç = self.fonksiyon(*args, **kwargs) bitiş = time.time() print(f"{self.fonksiyon.__name__} {bitiş - başlama} saniyede tamamlandı.") return sonuç @Zamanlayıcı def ağır_işlem(): toplam = sum(range(1000000)) return toplam ağır_işlem()
Pratik Kullanım Alanları
- Yetkilendirme Kontrolü: API çağrılarına erişim izni sağlamak.
- Önbellekleme (Caching): Fonksiyon sonuçlarını hafızada tutmak.
- Hata Yönetimi: Fonksiyonların hata almadan çalışmasını sağlamak.
- Günlük (Logging): Fonksiyon çağrılarını ve performansını kaydetmek.
- Performans Ölçümü: Zamanlayıcı dekoratörleriyle fonksiyonların hızını ölçmek.
Decorator Zincirleri (Birden Fazla Dekoratör Kullanımı)
Python’da bir fonksiyon birden fazla dekoratörle süslenebilir.
Örnek:
def dekor1(f): def sarmal(): print("Dekoratör 1") f() return sarmal def dekor2(f): def sarmal(): print("Dekoratör 2") f() return sarmal @dekor1 @dekor2 def fonksiyon(): print("Asıl Fonksiyon") fonksiyon()
Çıktı:
Dekoratör 1 Dekoratör 2 Asıl Fonksiyon
Sonuç
Python’da metaprogramlama ve dekoratörler, yazılım geliştirmeyi daha dinamik ve esnek hale getiren araçlardır. Bu teknikleri doğru kullanarak kodlarınızı daha temiz, esnek ve yeniden kullanılabilir hale getirebilirsiniz.