Python’da Kapsülleme (Encapsulation)
Bu derste, Python’da kapsülleme (encapsulation) konseptine odaklancağız. Kapsüllemenin, nesne tabanlı programlama içerisindeki önemini, nasıl çalıştığını ve nasıl etkili bir şekilde kullanıldığını detaylarıyla inceleyeceğiz.
Python’da Kapsülleme Niye Kullanılır?
Kapsülleme, bir nesnenin metotlarını, verilerini ve değişkenlerini diğer nesnelerden saklama ve bu özelliklere olan erişimi sınırlandırmaya yarar. Bu konsept, bu bilgilere yanlış ya da istenmeyen bir şekilde erişilmesini engelleyerek güvenliği artırır. Örneğin:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class BankaHesabi: def __init__(self, sahip, baslangic_bakiyesi=0): self.sahip = sahip self.bakiye = baslangic_bakiyesi def para_yatir(self, miktar): self.bakiye += miktar print(f"{miktar} TL yatırıldı. Güncel bakiye: {self.bakiye} TL") def para_cek(self, miktar): if miktar <= self.bakiye: self.bakiye -= miktar print(f"{miktar} TL çekildi. Güncel bakiye: {self.bakiye} TL") else: print("Yetersiz bakiye!") |
Şimdi ise bu sınıfın içindeki bilgilere dışarıdan doğrudan erişip değiştirelim ki tehlikesi görülsün:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
class BankaHesabi: def __init__(self, sahip, baslangic_bakiyesi=0): self.sahip = sahip self.bakiye = baslangic_bakiyesi def para_yatir(self, miktar): self.bakiye += miktar print(f"{miktar} TL yatırıldı. Güncel bakiye: {self.bakiye} TL") def para_cek(self, miktar): if miktar <= self.bakiye: self.bakiye -= miktar print(f"{miktar} TL çekildi. Güncel bakiye: {self.bakiye} TL") else: print("Yetersiz bakiye!") hesap = BankaHesabi("Ali", 500) print(hesap.bakiye) # Çıktı: 500 # Bakiyeye doğrudan erişip değiştirme: hesap.bakiye = 1000000 print(hesap.bakiye) # Çıktı: 1000000 |
Bu kodda, BankaHesabi
sınıfının bakiye özelliğine dışarıdan doğrudan erişip değerini değiştirdik. Bu, istenmeyen veya yanlışlıkla yapılan değişikliklere neden olabilir. Kapsülleme bu tür sorunları önlemek için önemlidir. Kodu çalıştırmak için: Trinket
Python’da “Kapsülleme” Nasıl Yapılır?
Kapsülleme, Python’da genellikle özelliklere (attributes) ve metotlara özel (private) ya da korunan (protected) erişim tanımlayarak gerçekleştirilir. Python’da tam anlamıyla özel bir erişim modifikatörü olmadığını belirtmemiz önemli. Ancak isimlendirme konvensiyonları ile bu özellik benzeri bir davranış elde edilebilir.
- Korunan (Protected) Nitelikler: Niteliğin önüne tek bir alt çizgi (
_
) ekleyerek bu niteliği koruma altına alabiliriz. Bu, niteliğin sadece sınıf içinden ve alt sınıflar tarafından erişilebilir olduğunu belirtir (fakat bu tam bir zorlama değil, sadece bir konvensiyon). - Özel (Private) Nitelikler: Niteliğin önüne çift alt çizgi (
__
) ekleyerek bu niteliği özel olarak tanımlayabiliriz. Bu durumda Python niteliği yeniden adlandırarak dışarıdan doğrudan erişime kapatır.
Örneğimize geri dönerek kapsüllemeyi nasıl uygulayacağımızı görelim:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class BankaHesabi: def __init__(self, sahip, baslangic_bakiyesi=0): self._sahip = sahip # korunan nitelik self.__bakiye = baslangic_bakiyesi # özel nitelik def para_yatir(self, miktar): self.__bakiye += miktar print(f"{miktar} TL yatırıldı. Güncel bakiye: {self.__bakiye} TL") def para_cek(self, miktar): if miktar <= self.__bakiye: self.__bakiye -= miktar print(f"{miktar} TL çekildi. Güncel bakiye: {self.__bakiye} TL") else: print("Yetersiz bakiye!") |
Bu sınıfta, __bakiye
adlı özel bir nitelik oluşturduk. Şimdi bu niteliğe dışarıdan doğrudan erişmeye çalıştığımızda bir hata alacağız:
1 2 |
hesap = BankaHesabi("Ali", 500) print(hesap.__bakiye) # Hata: 'BankaHesabi' object has no attribute '__bakiye' |
Ancak sınıfın içinde tanımlı metotlarla (para_yatir
, para_cek
) bu nitelikle etkileşim kurabiliriz.
Bu yöntem, sınıfın içerisindeki verilere veya fonksiyonlara dışarıdan yanlışlıkla veya kötü niyetle müdahale edilmesini önlemek için oldukça kullanışlıdır.
“get” ve “set” Metotları
Python’da, sınıfların içindeki özel veya korunan niteliklere dolaylı erişim sağlamak için genellikle “get” ve “set” adı verilen metotlar kullanılır. Bu metotlar, niteliklerin doğrudan erişimine izin vermeden onların değerlerini alma veya değiştirme işlemlerini kontrol altında tutmamıza olanak tanır. Ne işe yarıyormuş bunu da gösterelim:
- get Metodu: Niteliğin değerini döndürmek için kullanılır. Niteliğin doğrudan erişimine izin vermek yerine, niteliğin değerini bu metod üzerinden alabiliriz.
- set Metodu: Niteliğin değerini değiştirmek için kullanılır. Niteliğe değer atama işlemi yaparken bu metod üzerinden yaparak, atanan değerin geçerlilik kontrolü gibi ek kontrolleri uygulayabiliriz.
Bir kişinin yaşını temsil eden bir Yas
sınıfı düşünelim. Bu sınıf, yaşı doğrudan değiştirmek yerine, yaşın doğru ve geçerli bir değere sahip olup olmadığını kontrol etmek için “get” ve “set” metotlarını kullanacaktır.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
class Yas: def __init__(self, baslangic_yasi): self.__yas = baslangic_yasi # "get" metodu def get(self): return self.__yas # "set" metodu def set(self, y): if y >= 0: self.__yas = y else: print("Geçersiz yaş değeri!") kisi = Yas(25) print(kisi.get()) # Çıktı: 25 kisi.set(-5) # Çıktı: Geçersiz yaş değeri! print(kisi.get()) # Çıktı: 25 (yaş değişmedi) |
Bu metotlar her ne kadar genellikle get ve set olarak isimlendirilmiş olsa da, geliştiriciler diledikleri ismi verebilirler. Bakınız:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
class Yas: def __init__(self, baslangic_yasi): self.__yas = baslangic_yasi # "get" metodu def yasi_al(self): return self.__yas # "set" metodu def yasi_ayarla(self, y): if y >= 0: self.__yas = y else: print("Geçersiz yaş değeri!") kisi = Yas(25) print(kisi.yasi_al()) # Çıktı: 25 kisi.yasi_ayarla(-5) # Çıktı: Geçersiz yaş değeri! print(kisi.yasi_al()) # Çıktı: 25 (yaş değişmedi) |
Ancak, get ve set isimleri programlama jargonunda oldukça yaygın olduğu için bu isimleri kullanmak, kodun okunurluğunu ve başka geliştiriciler tarafından anlaşılabilirliğini arttırır.