3 - Kalıtım (Inheritance)
2026
Bu hafta, bir sınıftan başka bir sınıf türeterek ortak davranışları yeniden kullanmayı ve alt sınıflarla sınıfı daha özel hale getirmeyi ele alacağız.
Dersin sonunda şunları yapabiliyor olmanız beklenir:
__init__ yazarken super() ile taban kurulumunu sürdürmeksuper() zincirinin nasıl çalıştığını görmekisinstance() ve issubclass() ile tür ilişkisini kontrol etmeksuper() ile).Person ve Studentclass Person:
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
def print_name(self):
print(self.first_name, self.last_name)
# Taban sınıf örneği
p = Person("John", "Doe")
p.print_name() # John Doe
# Student sınıfı, Person'dan miras alıyor
class Student(Person):
pass # Şimdilik ek bir şey yapmıyoruz.
s = Student("Ali", "Veli")
s.print_name() # Ali Velipass notu
pass, “bu blok şimdilik boş; hata verme, devam et” anlamına gelir.
Önemli not
Bu sunumdaki kod parçaları bağımsız örneklerdir. Aynı dosyada ardışık çalıştırmak yerine, örnekleri tek tek değerlendirin.
__init__ Yazmazsak Ne Olur?Alt sınıf __init__ tanımlamazsa, Python taban sınıfın __init__ metodunu kullanır.
__init__ Yazınca: Neden super()?Alt sınıf __init__ tanımladığınız anda, taban sınıfın __init__ metodu otomatik olarak çalışmaz.
Bu nedenle taban sınıfın yaptığı kurulum (ör. first_name, last_name gibi niteliklerin oluşturulması) kaybolabilir.
Bu kurulumu korumak için taban sınıfın __init__ metodunu açıkça çağırırız. Python’da bunun standart yolu super().__init__(...) kullanmaktır.
Ne olur çağırmazsak? Tabanın oluşturması beklenen nitelikler oluşmayabilir ve daha sonra erişimde AttributeError görülebilir.
class Student(Person):
def __init__(self, first_name, last_name, year):
Person.__init__(self, first_name, last_name)
self.graduation_year = year
s = Student("Ali", "Veli", 2023)
s.print_name()
print(s.graduation_year)Uyarı
Bu yöntem çoklu mirasta kırılgan olabilir. Python’da genel tercih super() kullanmaktır.
super() ile __init__() Kullanımısuper(), alt sınıf içinden taban sınıfta tanımlı metotları çağırmak için kullanılır. Bu derste şimdilik super()’ı “taban sınıfın kurulumunu/metodunu çağırma” olarak düşünebilirsiniz; çoklu mirasta ayrıntısını ayrıca göreceğiz.
Override (yeniden tanımlama), alt sınıfın taban sınıfta bulunan bir metodu aynı adla yeniden yazarak kendi davranışını tanımlamasıdır. Alt sınıf nesnesinde bu metot çağrıldığında, tabandaki sürüm yerine alt sınıftaki sürüm çalışır.
Genişletme (extend), taban sınıftaki metodu tamamen değiştirmek yerine, tabanın yaptığı işi koruyup üzerine yeni adımlar eklemektir. Bu yaklaşımda çoğunlukla super() ile taban sınıfın metodu çağrılır, ardından alt sınıfa özgü ek davranış eklenir.
Kalıtımın önemli çıktılarından biri polimorfizmdir: aynı metot adı, farklı sınıflarda farklı davranış üretir.
Kalıtım çoğunlukla şu ilişki doğruysa anlamlıdır:
Student, Person türüdür.Buna karşılık, şu ilişki daha çok bileşim (composition) gerektirir:
Car bir Engine türü değildir; motor araçta bir parçadır.isinstance() ve issubclass() Nedir?Bu iki fonksiyon, kalıtım ilişkilerini kontrol etmek için kullanılır:
isinstance(nesne, Sinif): “Bu nesne, bu sınıftan (veya onun alt sınıflarından) mı?”issubclass(AltSinif, UstSinif): “Bu sınıf, bu sınıfın alt sınıfı mı?”Ek not
isinstance(nesne, (A, B)) biçiminde birden fazla sınıfı aynı anda kontrol edebilirsiniz.
isinstance() / issubclass() ÖrnekleriBu örnekte:
guc).puan) günceller.Oyuncuclass Oyuncu:
def __init__(self, isim, unvan):
self.isim = isim
self.unvan = unvan
self.guc = 0
self.puan = 0
def hareket_et(self):
print("Hareket ediyor...")
def puan_kazan(self, miktar=10):
self.puan += miktar
print(f"Puan +{miktar} -> {self.puan}")
def puan_kaybet(self, miktar=5):
self.puan -= miktar
print(f"Puan -{miktar} -> {self.puan}")Burada “daha özel” derken, taban sınıfın genel tanımına ek özellik/kısıt ekleyerek daha dar bir tür tanımlamayı kastediyoruz.
class Asker(Oyuncu):
def __init__(self, isim, unvan):
super().__init__(isim, unvan)
self.guc = 100
def hareket_et(self):
super().hareket_et()
print("Hedefe ulasti.")
class Isci(Oyuncu):
def __init__(self, isim, unvan):
super().__init__(isim, unvan)
self.guc = 70
class Yonetici(Oyuncu):
def __init__(self, isim, unvan):
super().__init__(isim, unvan)
self.guc = 50asker = Asker("Ahmet", "Binbasi")
isci = Isci("Mehmet", "Usta")
yonetici = Yonetici("Selim", "Mudur")
print(asker.isim, asker.unvan, asker.guc) # Ahmet Binbasi 100
asker.hareket_et()
isci.puan_kazan(20)
yonetici.puan_kaybet(15)
print(isinstance(asker, Oyuncu)) # True
print(issubclass(Asker, Oyuncu)) # TruePython’da bir sınıf birden fazla sınıftan miras alabilir.
SomeClass.mro() veya SomeClass.__mro__ ile görebiliriz.FlyingCar(Flyable, Car) ile FlyingCar(Car, Flyable) farklı sıralar üretir.super() Nasıl Çalışır?Çoklu mirasta super() çoğu zaman “doğrudan ebeveyn” anlamına gelmez.
super(), MRO sırasına göre bir sonraki sınıfa geçer.
Bu sayede sınıflar bir zincir gibi sırayla çalışabilir.
super() Zinciri (İşbirlikçi Yaklaşım)Amaç, MRO zincirindeki sınıfların her birinin katkı yapabilmesidir.
Bu yüzden (özellikle aynı metot adı etrafında) her sınıf uygun yerde super() çağırarak zinciri sürdürür.
Car, Flyable, FlyingCarBu örnekte:
go() ve fly() ayrı davranışlar olarak miras alınır.start() ise zincir mantığıyla, MRO üzerinden katkıların sıralanmasını gösterir.class Startable:
def start(self):
print("Start sequence:")
class Car(Startable):
def go(self):
print("Going")
def start(self):
super().start()
print(" - engine on")
class Flyable(Startable):
def fly(self):
print("Flying")
def start(self):
super().start()
print(" - rotors on")
class FlyingCar(Flyable, Car):
def start(self):
super().start()Eğer aradaki bir sınıf, ilgili metotta super() çağırmazsa zincir MRO boyunca ilerlemez ve bazı sınıfların katkısı devreye girmeyebilir.
passsuper() ile)*args / **kwargs ile Parametre Aktarımıclass Student(Person):
def __init__(self, *args, year, **kwargs):
super().__init__(*args, **kwargs)
self.graduation_year = year
s = Student("Ali", "Veli", year=2023)
s.print_name()
print(s.graduation_year)Not: year burada keyword-only argümandır; çağrıda year=... yazmak gerekir.
Amaç: Alt sınıfta bir metodu override ederek davranışı değiştirmek.
Görev:
Kisi adında bir taban sınıf yazın:
ad, soyadyazdir() → ekrana ad soyad yazsın.Ogretmen(Kisi) adında bir alt sınıf yazın:
bransyazdir() metodunu override edin → ekrana ad soyad - brans yazsın.Kontrol kodu:
Beklenen çıktı:
Ayse Yilmaz - Matematik
Görev:
Araba sınıfı yazın:
baslat() → Araba basladi yazsın.Tekne sınıfı yazın:
baslat() → Tekne basladi yazsın.AmfibiArac(Araba, Tekne) sınıfını yazın.
AmfibiArac().baslat() hangi metodu çalıştırıyor gözlemleyin.
AmfibiArac.mro() çıktısını yazdırın.
Kontrol kodu:
Beklenen:
baslat() çağrısında hangi sınıfın metodu çalışıyorsa onu görmelisiniz.mro() listesinde sınıfların sırası yazmalıdır.Amaç: Aynı metot adının farklı sınıflarda farklı davranış üretmesini görmek.
Görev:
Oyuncu taban sınıfını yazın:
ad niteliği tanımlayın.yetenek_kullan() → Oyuncu yetenek kullandi yazsın.Savasci(Oyuncu), Buyucu(Oyuncu), Okcu(Oyuncu) alt sınıflarını yazın:
yetenek_kullan() metodunu override edin ve her biri farklı mesaj yazsın.oyuncular listesine koyup döngüyle yetenek_kullan() çağırın.Kontrol kodu:
Beklenen:
super()Amaç: Taban davranışını koruyup üzerine ek davranış eklemek (extend).
Görev:
Kisi taban sınıfı:
yazdir() → ad soyad yazsın.
Ogrenci(Kisi) alt sınıfı:
Ek nitelik: numara
yazdir() metodunu override edin ama genişletme yapın:
super().yazdir() çağırın,Numara: ... yazdırın.Kontrol kodu:
Beklenen çıktı:
Ali Veli
Numara: 123
super() bu sıraya göre “bir sonraki” sınıfa geçer.isinstance() ve issubclass() kalıtım ilişkilerini kontrol etmek için kullanılır.