Kurs
Kapsülleme, Python’daki temel nesne yönelimli ilkelerden biridir. Sınıflarınızı kazara yapılan değişiklik veya silinmelere karşı korur ve kodun yeniden kullanılabilirliğini ve sürdürülebilirliğini artırır. Şu basit sınıf tanımını düşünün:
class Smartphone:
def __init__(self, brand, os):
self.brand = brand
self.os = os
iphone = Smartphone("Apple", "iOS 17")
Birçok Python programcısı sınıfları bu şekilde tanımlar. Ancak bu, profesyonel Python geliştiricilerinin takip ettiği en iyi uygulamalardan oldukça uzaktır. Bu sınıftaki sorun, verilerini değiştirmeye çalıştığınızda açıkça ortaya çıkar:
iphone.os = "Android"
print(iphone.os)
Android
Android çalıştıran bir iPhone hayal edin — ne büyük bir aykırılık! Açıkça görülüyor ki, kullanıcıların özniteliklerini istedikleri gibi değiştirmelerini engellemek için sınıfımız içinde bazı sınırlar koymamız gerekiyor.
Eğer değiştirmeye karar verirlerse, bu değişiklikler bizim şartlarımız ve kurallarımız doğrultusunda yapılmalı. Yine de yüzeyde .os veya .brand özniteliklerinin aynı kalmasını istiyoruz.
Tüm bunlar kapsüleme kullanılarak desteklenebilir ve bu derste bununla ilgili her şeyi öğreneceğiz. Hadi başlayalım!
Python’da Kapsülleme Nasıl Sağlanır?
Python, zorunlu erişim belirleyicileri yerine, sözleşmeler ve programlama uygulamaları aracılığıyla kapsülemeyi destekler. Şöyle ki, Python kod tasarımının büyük bölümünün arkasındaki temel ilke “Burada hepimiz yetişkiniz.” anlayışıdır. Kapsülemeyi yalnızca bir sözleşme olarak uygulayabilir ve diğer Python geliştiricilerinin kodumuza güvenip saygı göstereceğini umabiliriz.
Java ve C++ gibi diğer OOP dillerinde kapsülleme, public, private veya protected gibi erişim belirleyicileriyle sıkı şekilde uygulanır, ancak Python’da bunlar yoktur:
| Özellik | Python | Java | C++ |
|---|---|---|---|
| Erişim belirleyicileri | Zorunlu belirleyiciler yok; adlandırma sözleşmeleri kullanılır (_protected, __private) |
public, protected, private anahtar sözcükleriyle uygulanır |
public, protected, private anahtar sözcükleriyle uygulanır |
| Getter/setter yöntemleri | İsteğe bağlıdır, genellikle kontrollü erişim için @property dekoratörüyle kullanılır |
Yaygın uygulama, genellikle yöntemler olarak uygulanır | Yaygın uygulama, genellikle yöntemler olarak uygulanır |
| Veri Erişimi | Adlandırma sözleşmeleriyle erişilebilir; geliştirici disiplinine dayanır | Erişim belirleyicileriyle kontrol edilir; derleyici tarafından zorlanır | Erişim belirleyicileriyle kontrol edilir; derleyici tarafından zorlanır |
| Felsefe | “Burada hepimiz yetişkiniz” - sözleşmelere ve güvene dayanır | Erişim kontrolünün sıkı şekilde uygulanması | Erişim kontrolünün sıkı şekilde uygulanması |
Dolayısıyla, size göstermek üzere olduğum kapsülleme tekniklerinin çoğu, hatta tamamı Python sözleşmeleridir. İsterseniz kolayca bozulabilirler. Ancak kendi geliştirme projelerinizde bunlara saygı göstereceğinize ve uyacağınıza güveniyorum.
Python’da erişim belirleyicileri
Diyelim ki şöyle basit bir sınıfımız var:
class Tree:
def __init__(self, height):
self.height = height
pine = Tree(20)
print(pine.height)
20
Yazdırabildiğimiz tek bir height özniteliği var. Sorun şu ki, bunu istediğimiz herhangi bir şeye de çevirebiliriz:
pine.height = 50
pine.height
50
pine.height = "Grandma"
pine.height
'Grandma'
Peki kullanıcılara, height’ı değiştirmenin yasak olduğunu nasıl söyleriz? Bir korumalı üyeye çevirerek; bunun için başına tek alt çizgi ekleriz:
class Tree:
def __init__(self, height):
self._height = height
pine = Tree(20)
pine._height
20
Artık bu sözleşmeyi bilen kişiler, özniteliğe yalnızca erişebileceklerini ve onu kullanıp değiştirmelerinin şiddetle tavsiye edilmediğini anlayacaktır. Ama isterlerse değiştirebilirler, evet.
Öyleyse bunu da nasıl önleriz? Başka bir sözleşme kullanarak — özniteliği başına çift alt çizgi ekleyerek bir özel üyeye dönüştürerek:
class Tree:
def __init__(self, height):
self.__height = height
pine = Tree(20)
pine.__height
AttributeError: 'Tree' object has no attribute '__height'
Artık biri özniteliğe erişmeye çalışırsa, değiştirmeyi bırakın, Python bir hata yükseltecek.
Ama ne yaptığımızın farkında mısınız? Nesnelerimizle ilgili tek bilgiyi kullanıcıdan gizledik. Sınıfımız halka açık öznitelik olmadığından işe yaramaz hale geldi.
Peki ağaç yüksekliğini kullanıcılara nasıl açarız ama yine de nasıl erişilip değiştirileceğini kontrol ederiz? Örneğin, ağaç yüksekliklerinin belirli bir aralıkta ve yalnızca tam sayı olmasını istiyoruz. Bunu nasıl zorunlu kılarız?
Bu noktada, Java kullanan bir arkadaşınız devreye girip getter ve setter yöntemleri kullanmayı önerebilir. O halde önce bunu deneyelim:
class Tree:
def __init__(self, height):
self.__height = height
def get_height(self):
return self.__height
def set_height(self, new_height):
if not isinstance(new_height, int):
raise TypeError("Tree height must be an integer")
if 0 < new_height <= 40:
self.__height = new_height
else:
raise ValueError("Invalid height for a pine tree")
pine = Tree(20)
pine.get_height()
20
Bu şekilde, __height adlı bir özel öznitelik oluşturur, ancak kullanıcıların buna get_height ve set_height yöntemlerini kullanarak kontrollü bir şekilde erişip değiştirmesine izin verirsiniz.
pine.set_height(25)
pine.get_height()
25
set_height, yeni bir değer ayarlamadan önce yeni yüksekliğin belirli bir aralıkta ve sayısal olduğundan emin olur.
pine.set_height("Password")
TypeError: Tree height must be an integer
Ancak bu yöntemler basit bir işlem için biraz abartı görünüyor. Ayrıca, şu şekilde kod yazmak da pek hoş değil:
# Increase height by 5
pine.set_height(pine.get_height() + 5)
Şu kodu yazabilsek daha güzel ve okunaklı olmaz mıydı:
pine.height += 5
ve yine de height için doğru veri türünü ve aralığı zorunlu kılsak? Cevap evet ve bir sonraki bölümde tam olarak bunu nasıl yapacağımızı öğreneceğiz.
Python sınıflarında @property dekoratörünü kullanma
Yeni bir teknik tanıtıyoruz — öznitelikler için property oluşturma:
class Tree:
def __init__(self, height):
# First, create a private or protected attribute
self.__height = height
@property
def height(self):
return self.__height
pine = Tree(17)
pine.height
17
Kullanıcıların __height adlı gizli bir özniteliğe, sanki height adlı normal bir öznitelikmiş gibi erişmesini istiyoruz. Bunu başarmak için, self.__height döndüren ve @property ile dekore edilen height adlı bir yöntem tanımlarız.
Artık height çağrılarak özel özniteliğe erişilebilir:
pine.height
17
Ancak en iyi yanı, kullanıcıların bunu değiştiremiyor olmasıdır:
pine.height = 15
AttributeError: can't set attribute 'height'
Bu yüzden, height.setter dekoratörüyle sarmalanan height(self, new_height) adlı başka bir yöntem ekleriz. Bu yöntemin içinde, height için istenen veri türünü ve aralığı zorunlu kılan mantığı uygularız:
class Tree:
def __init__(self, height):
self.__height = height
@property
def height(self):
return self.__height
@height.setter
def height(self, new_height):
if not isinstance(new_height, int):
raise TypeError("Tree height must be an integer")
if 0 < new_height <= 40:
self.__height = new_height
else:
raise ValueError("Invalid height for a pine tree")
Artık bir kullanıcı height özniteliğini değiştirmeye çalıştığında, @height.setter çağrılır ve böylece doğru değerin geçirildiğinden emin olunur:
pine = Tree(10)
pine.height = 33 # Calling @height.setter
pine.height = 45 # An error is raised
ValueError: Invalid height for a pine tree
@height.getter ile, height özniteliğine nokta gösterimiyle erişimin şeklini de özelleştirebiliriz:
class Tree:
def __init__(self, height):
self.__height = height
@property
def height(self):
return self.__height
@height.getter
def height(self):
# You can return a custom version of height
return f"This tree is {self.__height} meters"
pine = Tree(33)
pine.height
'This tree is 33 meters'
pine’ı tam sayı bir yükseklikle oluşturmuş olsak da, değerini @height.getter ile değiştirebildik.
Bunlar, bir Python sınıfında kapsülemeyi nasıl teşvik edebileceğimize dair örneklerdi. Unutmayın, kapsülleme hâlâ bir sözleşmedir çünkü dahili __height özel üyesini yine de bozabiliriz:
pine._Tree__height = "Gotcha!"
pine.height
'This tree is Gotcha! meters'
Python sınıflarındaki her şey özeldir demiyoruz; aksine her şey genelde herkese açıktır ve özel yöntemler de öyledir. Bu bir tasarım hatası değil, “Burada hepimiz yetişkiniz” yaklaşımının bir yansımasıdır.
İşte az önce gözden geçirdiğimiz Python erişim belirleyicilerine genel bir bakış:
| Belirleyici/Sözleşme | Açıklama | Örnek |
|---|---|---|
| Public | Varsayılan erişim düzeyi; öznitelik ve yöntemlere sınıfın dışından erişilebilir | self.attribute |
| Protected | Tek alt çizgi ile belirtilir; kısmen kısıtlı erişimi ifade eden bir sözleşme | self._attribute |
| Private | Çift alt çizgi ile belirtilir; ad karmaşası sınırlı erişim kısıtlaması sağlar | self.__attribute |
| Property’ler | @property decorator kullanarak özel özniteliklere kontrollü erişim sağlar |
@property def attribute(self): |
| Salt-okunur Property’ler | @attribute.setter yoktur; bir özniteliğe yalnızca okuma erişimi sağlar |
@property def attribute(self): |
Kapsülleme Uygularken En İyi Uygulamalar
Kodunuzun diğer deneyimli OOP’cuların yazdığı kodla iyi hizalanmasını sağlamak için takip edebileceğiniz bazı en iyi uygulamalar şunlardır:
- Yalnızca sizin kullandığınız öznitelik veya yöntemler için korumalı ya da özel üyeler oluşturun. Korumalı veya özel üyeler dokümantasyondan hariç tutulur ve geliştirici olarak sizin haber vermeden değiştirebileceğinizi işaret eder; böylece başkalarının bunları kullanmasını caydırır.
- Her bir sınıf özniteliği için mutlaka property oluşturmanız gerekmez. Çok sayıda özniteliği olan büyük sınıflarda
attr.getterveattr.setteryazmak baş ağrısına dönüşebilir. - Bir kullanıcı korumalı bir üyeye (
_) her eriştiğinde uyarı vermeyi değerlendirin. - Özel üyeleri ölçülü kullanın, çünkü sözleşmeye aşina olmayanlar için kodu okunaksız hale getirebilirler.
- Açıklı ğa kapalılıktan öncelik verin. Kapsülleme, kodun bakımını ve veri korumasını iyileştirmeyi amaçlar; bu nedenle sınıfınızın önemli uygulama ayrıntılarını tamamen gizlemeyin.
- Salt-okunur property’ler oluşturmak istiyorsanız,
@attr.setteryöntemini uygulamayın. Kullanıcılar property’ye erişebilir ama onu değiştiremez. - Kapsüllemenin bir sözleşme olduğunu, Python söz diziminin zorladığı bir özellik olmadığını her zaman hatırlayın.
- Basit sınıflar için dataclass’ları kullanmayı düşünün; tek satırlık bir kodla sınıf kapsüllemesini etkinleştirmenize olanak tanırlar. Ancak dataclass’lar, öznitelik ve yöntemleri öngörülebilir daha basit sınıflar içindir. Daha fazla bilgi için bu dataclass’lar dersine göz atın.
Sonuç ve Ek Kaynaklar
Bu derste, Python’da nesne yönelimli programlamanın temel direklerinden birini öğrendik: kapsülleme.
Kapsülleme, sınıfınızın nesneleri içinde depolanan verilere kontrollü erişim tanımlamanızı sağlar. Bu sayede temiz, okunabilir ve verimli kod yazabilir, sınıf verilerinizin kazara değiştirilmesini veya silinmesini önleyebilirsiniz.
OOP bilginizi artırmak için bazı ilgili kaynaklar:
FAQs
Python’da kapsülleme soyutlamadan nasıl farklıdır?
Kapsülleme; veriyi ve bu veri üzerinde çalışan yöntemleri bir birim (ör. sınıf) içinde bir araya getirmek ve bazı bileşenlere erişimi kısıtlamakla ilgilidir. Soyutlama ise karmaşık gerçeği saklayıp yalnızca öz olan kısımları ortaya çıkarmakla ilgilidir. Kapsülleme erişimi kısıtlamaya odaklanırken, soyutlama etkileşimleri basitleştirmeye odaklanır.
Kapsülleme fonksiyonel programlamada kullanılabilir mi, yoksa yalnızca OOP’ye mi özgüdür?
Kapsülleme, nesne yönelimli programlama (OOP) ile yakından ilişkili bir kavramdır ve genellikle fonksiyonel programlamada kullanılmaz. Fonksiyonel programlama, OOP’nin nesnelere ve veriyi bu nesnelerin içinde kapsüllemeye odaklanmasının aksine, değişmezlik ve durumdan bağımsız işlevleri vurgular.
Python’da kapsüllemeyi uygularken kaçınılması gereken yaygın tuzaklar nelerdir?
Yaygın tuzaklar arasında, kodun bakımını zorlaştırabilen özel değişkenlerin aşırı kullanımı ve yeterli erişim yöntemleri (getter/setter) sağlamamak bulunur; bu da kırılgan koda yol açabilir. Ayrıca geliştiriciler Python’daki kapsüllemenin bir sözleşme olduğunu ve bu nedenle baypas edilebileceğini unutabilir.
Kapsülleme kod güvenliğini nasıl artırabilir?
Kapsülleme, bir nesnenin iç durumuna erişimi kısıtlayarak ve yetkisiz değişiklikleri önleyerek kod güvenliğini artırabilir. Verinin nasıl erişilip değiştirildiğini kontrol ederek, verinin geçerli ve tutarlı kalmasını sağlayabilirsiniz.
@property dekoratörünün kullanımı Python’da performansı nasıl etkiler?
@property dekoratörünü kullanmak, ekstra yöntem çağrıları nedeniyle küçük bir ek yük getirebilir, ancak çoğu durumda bu etki önemsizdir. Geliştirilmiş kod okunabilirliği ve sürdürülebilirliğin faydaları, genellikle bu küçük performans maliyetlerinden daha ağır basar.
Python’da kapsüllemeyi Java veya C++’taki gibi sıkı şekilde uygulamak mümkün mü?
Python, Java veya C++ gibi kapsüllemeyi sıkı şekilde uygulamaz. Felsefesi, geliştiricilerin özel ve korumalı üyelerin amaçlanan kullanımına saygı göstereceği anlayışı ve sözleşmelere dayanır. Yine de alt çizgi gibi adlandırma sözleşmeleri, yanlış kullanımı caydırabilir.
Python projelerinde kapsülemenin gerçek dünya uygulamaları nelerdir?
Kapsülleme; banka yazılımları gibi hassas verilerin korunduğu uygulamalarda, hesap ayrıntılarının gizlenmesinde kullanılır. Ayrıca kitaplık ve çerçevelerde, geliştiricilerin basit arabirimlerle etkileşime girmesine olanak tanımak için karmaşık uygulama ayrıntılarını gizlemek amacıyla da kullanılır.
Python’da kapsüllenmiş kodu etkili biçimde nasıl test edebilirim?
Kapsüllenmiş kodu test etmek, bir sınıfın herkese açık arabirimi için birim testleri yazmayı içerir. Kullanıcıya sunulan yöntem ve property’leri test ederek dahili durum değişikliklerinin doğru yönetildiğinden ve kapsülleme mantığının korunduğundan emin olursunuz.
Kapsülleme Python modüllerine uygulanabilir mi, yoksa sınıflarla mı sınırlıdır?
Kapsülleme esas olarak sınıflarla ilişkilidir, ancak kavram modüllere de genişletilebilir; modül içinde özel kullanım sinyali vermek için alt çizgi ile başlayan işlevler veya değişkenler kullanılabilir.
Kapsülleme, Python’da polimorfizmle nasıl ilişkilidir?
Kapsülleme ve çok biçimlilik (polimorfizm) her ikisi de OOP ilkeleridir ancak farklı amaçlara hizmet eder. Kapsülleme, bir nesnenin belirli kısımlarına erişimi kısıtlarken, polimorfizm nesnelerin üst sınıflarının örnekleri gibi ele alınmasına olanak tanır ve kodun genişletilmesini ve bakımını kolaylaştırır. Birlikte kullanıldıklarında esnek ve güvenli kod yapıları oluşturabilirler.
2 yılı aşkın deneyime sahip bir veri bilimi içerik üreticisiyim ve Medium’da en büyük takipçi kitlelerinden birine sahibim. Yapay zekâ ve makine öğrenimi üzerine, biraz da alaycı bir üslupla yazılmış, ayrıntılı makaleler kaleme almayı seviyorum; çünkü onları biraz daha az sıkıcı hale getirmek için bir şeyler yapmak gerekiyor. 130’un üzerinde makale ve bir de DataCamp kursu ürettim; bir diğeri de hazırlık aşamasında. İçeriklerim 5 milyondan fazla kişi tarafından görüldü; bunların 20 bini Medium ve LinkedIn’de takipçim oldu.

