Dönem Sonu Özeti
2026
Bu sunumda konuları en baştan yeniden anlatmayacağız.
Amaç:
Bu dönem şu çizgide ilerledik:
self, __init__super(), override@property, soyutlamaOOP’de amaç yalnızca sınıf yazmak değildir.
Asıl amaç:
class Ogrenci:
def __init__(self, ad, numara):
self.ad = ad
self.numara = numara
def bilgi_ver(self):
return f"{self.ad} - {self.numara}"Bu örnekte:
Ogrenci → SınıfOgrenci("Ayşe", 123) → Nesnead, numara → Nitelikbilgi_ver() → Metot__init__ ve self__init__, nesnenin ilk durumunu ayarlar.
self, metot içinde o anki nesneyi temsil eder.
class Ders:
def __init__(self, kod, ad):
self.kod = kod
self.ad = ad
self.ogrenciler = []
def ogrenci_ekle(self, ogrenci):
self.ogrenciler.append(ogrenci)Şu çağrıda:
Python, ders nesnesini metoda otomatik olarak gönderir.
universite → Sınıf niteliğiad → Örnek niteliğiDikkat edilmesi gereken nokta:
Sınıf niteliği tüm nesneler tarafından paylaşılır. Liste gibi değiştirilebilir yapılar sınıf düzeyinde tutulursa nesneler aynı listeyi paylaşabilir.
class Ders:
toplam_ders = 0
def __init__(self, ad):
self.ad = ad
Ders.toplam_ders += 1
@classmethod
def ders_sayisi(cls):
return cls.toplam_ders
@staticmethod
def gecer_not_mu(not_degeri):
return not_degeri >= 60Kısa ayrım:
self → Nesneye erişir.cls → Sınıfa erişir.is-a İlişkisiclass Kisi:
def __init__(self, ad):
self.ad = ad
class Ogrenci(Kisi):
def __init__(self, ad, numara):
super().__init__(ad)
self.numara = numaraKalıtım için temel soru:
Öğrenci gerçekten bir kişi türü müdür?
Cevap evetse kalıtım düşünülebilir.
super()Alt sınıf, üst sınıftaki metodu yeniden tanımlayabilir.
class Kisi:
def bilgi_ver(self):
return self.ad
class Ogrenci(Kisi):
def bilgi_ver(self):
return f"{super().bilgi_ver()} - {self.numara}"Burada:
bilgi_ver() override edilmiştir.super() ile üst sınıftaki davranış korunmuştur.@propertyKapsülleme, nesnenin iç durumunu kontrollü biçimde yönetmektir.
class Ders:
def __init__(self, ad, kredi):
self.ad = ad
self.kredi = kredi # setter çalışır
@property
def kredi(self):
return self._kredi
@kredi.setter
def kredi(self, deger):
if deger <= 0:
raise ValueError("Kredi pozitif olmalıdır")
self._kredi = deger__init__ içinde self.kredi = kredi yazıldığında doğrudan _kredi atanmaz; setter metodu çalışır.
Soyutlama, ayrıntıları gizleyip gerekli arayüzü öne çıkarır.
from abc import ABC, abstractmethod
class Raporlayici(ABC):
@abstractmethod
def rapor_uret(self, ders):
passBu yapı alt sınıfları rapor_uret() metodunu yazmaya zorlar.
Yani ortak bir kontrat tanımlar.
has-a İlişkisiclass NotKaydi:
def __init__(self, ogrenci, puan):
self.ogrenci = ogrenci
self.puan = puan
class Ders:
def __init__(self, ad):
self.ad = ad
self.notlar = []
def not_ekle(self, kayit):
self.notlar.append(kayit)Temel ilişki:
Ders, not kayıtlarına sahiptir.
Kısa karar sorusu:
is-a → Kalıtımhas-a → KompozisyonÖrnek:
Ogrenci, Kisi türüdür → KalıtımDers, NotKaydi içerir → KompozisyonSırf kod tekrarını azaltmak için kalıtım kullanmak çoğu zaman iyi bir tercih değildir.
Polimorfizm, aynı çağrının farklı nesnelerde farklı davranabilmesidir.
class PDFRapor:
def rapor_uret(self, ders):
return f"{ders.ad} PDF raporu"
class HTMLRapor:
def rapor_uret(self, ders):
return f"{ders.ad} HTML raporu"
raporlayicilar = [PDFRapor(), HTMLRapor()]
for raporlayici in raporlayicilar:
print(raporlayici.rapor_uret(ders))Kod, nesnenin tam sınıfını sormaz.
Python’da ortak davranış bazen ortak üst sınıftan daha önemlidir.
Burada raporlayici nesnesinin hangi sınıftan geldiği değil, şu davranışı sağlayıp sağlamadığı önemlidir:
Yalnızca metot adının aynı olması yetmez; metodun beklenen şekilde kullanılabilmesi gerekir.
Özel metotlar, kendi sınıflarımızı Python’ın yerleşik davranışlarıyla uyumlu hâle getirir.
class Ders:
def __init__(self, kod, ad):
self.kod = kod
self.ad = ad
self.ogrenciler = []
def __str__(self):
return f"{self.kod} - {self.ad}"
def __len__(self):
return len(self.ogrenciler)print(ders) → __str__len(ders) → __len____str__ ve __repr__İkisi de nesnenin metinsel temsilini verir; amaçları farklıdır.
def __str__(self):
return f"{self.kod} - {self.ad}"
def __repr__(self):
return f"Ders('{self.kod}', '{self.ad}')"__str__ → Kullanıcıya daha okunabilir çıktı__repr__ → Geliştiriciye daha açıklayıcı çıktıDekoratör, bir fonksiyonun davranışını fonksiyonun içini değiştirmeden genişletir.
Python’da fonksiyonlar da nesnedir.
Bu yüzden fonksiyonlar:
ogrenciler = [
("Ayşe", 85),
("Mehmet", 62),
("Zeynep", 94),
]
sirali = sorted(ogrenciler, key=lambda x: x[1], reverse=True)Kısa yazmak her zaman daha anlaşılır kod anlamına gelmez.
Iterable, üzerinde dolaşılabilen yapıdır.
Iterator, sıradaki elemanı üreten nesnedir.
for döngüsü perde arkasında iter() ve next() mantığıyla çalışır.
Generator, değerleri ihtiyaç oldukça üretir.
def notlari_oku(dosya_yolu):
with open(dosya_yolu, encoding="utf-8") as dosya:
for satir in dosya:
ad, puan = satir.strip().split(",")
yield ad, int(puan)Kullanım:
Avantaj:
Tüm dosyayı baştan belleğe almak yerine satır satır işlem yapılır.
Type hints, kodun hangi türlerle çalıştığını görünür yapar.
Önemli nokta:
Type hints, Python’da otomatik çalışma zamanı tür kontrolü yapmaz.
Daha çok:
için kullanılır.
SOLID, tasarım problemlerini fark etmek için kullanılır.
Tek Sorumluluk Prensibi
(Single Responsibility Principle)
Bir sınıf çok fazla iş mi yapıyor?
Açık/Kapalı Prensibi
(Open/Closed Principle)
Yeni özellik eklemek için sürekli eski kodu mu değiştiriyoruz?
Liskov Yerine Geçme Prensibi
(Liskov Substitution Principle)
Alt sınıf, üst sınıfın yerine sorunsuz geçebiliyor mu?
Arayüz Ayrımı Prensibi
(Interface Segregation Principle)
Sınıflar kullanmadığı metotlara zorlanıyor mu?
Bağımlılık Tersine Çevirme Prensibi
(Dependency Inversion Principle)
Üst seviye kod somut sınıflara fazla mı bağlı?
Amaç prensip adlarını ezberlemek değil, tasarım problemlerini tanımaktır.
Tasarım desenleri, sık karşılaşılan yazılım problemleri için kullanılan genel çözüm kalıplarıdır.
Bu dönem gördüklerimiz:
Desenler hazır kopyalanacak kodlar değildir.
Asıl değerleri, problemi nasıl düşündürdükleridir.
Tek nesne yeterli olmalı
→ Singleton
Nesne oluşturma kararı merkezi ve esnek olmalı
→ Factory Method
Nesneye çalışma zamanında ek davranış verilmeli
→ Decorator
Bir değişiklikten başka nesneler haberdar edilmeli
→ Observer
Algoritma çalışma zamanında değiştirilebilmeli
→ Strategy
Unit test, kodun küçük ve bağımsız parçalarını sınar.
def ortalama(vize, final):
return vize * 0.4 + final * 0.6
def test_ortalama():
assert ortalama(50, 80) == 68pytest ile bu test doğrudan çalıştırılabilir.
Test yazarken yalnızca fonksiyonu çağırmak yetmez; beklenen sonucu açıkça kontrol etmek gerekir.
Mocking, dış bağımlılıkları test sırasında taklit etmektir.
Kullanım nedenleri:
TDD döngüsü:
Debugging, hatayı yalnızca görmek değil, nedenini anlamaktır.
Araçlar:
print()breakpoint()pdbTemel akış:
Üçü aynı şey değildir.
threading
Bekleme içeren işleri aynı zaman aralığında yönetmek için kullanılır.
multiprocessing
CPU yoğun işleri farklı process’lere bölmek için kullanılır.
asyncio
Çok sayıda bekleyen görevi tek akış içinde yönetmek için kullanılır.
Temel soru:
Program daha çok bekliyor mu, yoksa daha çok hesaplama mı yapıyor?
| Durum | Daha uygun yaklaşım |
|---|---|
| Dosya indirme, ağ isteği, bekleme ağırlıklı işler | threading veya asyncio |
| CPU yoğun hesaplama | multiprocessing |
| Çok sayıda bağlantıyı tek akışta yönetme | asyncio |
| Paylaşılan veri thread’ler arasında değişiyor | Lock gerekir |
Önemli ayrım:
Bekleme ağırlıklı iş ile hesaplama ağırlıklı iş aynı problem değildir.
__init__, nesnenin ilk durumunu ayarlar.self elle gönderilmez; Python otomatik geçirir.Bir OOP kodu gördüğünüzde şunları sorun:
self, cls veya hiçbirini kullanıyor mu?is-a mı, has-a mı?Bu dönemin ana fikri şudur:
İyi OOP kodu, sınıf sayısının fazla olmasıyla değil; sorumlulukların doğru dağıtılmasıyla ortaya çıkar.
İyi tasarlanmış kod:
Dönem boyunca gösterdiğiniz ilgi ve katılım için teşekkür ederim.
Başarılar dilerim.