Nesne Tabanlı Programlama 2

3 - Kalıtım (Inheritance)

Emre Can Yılmaz

Ondokuz Mayıs Üniversitesi

2025

Kalıtım (Inheritance) ve İleri Konular

  • Nesne yönelimli programlama (OOP), gerçek dünya problemlerini nesneler aracılığıyla modelleyerek çözer.
  • Python, basit sözdizimi ve güçlü OOP desteği ile öne çıkar.
  • Bu sunumda kalıtım (inheritance) kavramını, temel örneklerden başlayarak ileri konulara kadar örneklerle inceleyeceğiz.
  • Ayrıca, grafik arayüz tasarımı gibi ileri uygulama alanlarında kalıtımın rolüne değineceğiz.

Temel Kavramlar

Kalıtım (Inheritance): - Mevcut bir sınıfın (taban/ebeveyn) özelliklerini ve metotlarını devralarak yeni sınıflar (alt/süreç) oluşturma mekanizması.

Taban Sınıf (Superclass / Base Class): - Ortak özellik ve metotların tanımlandığı sınıf.

Alt Sınıf (Subclass / Derived Class): - Taban sınıftan miras alır; ek özellik veya davranış eklenebilir.

Basit Örnek: Person ve Student

class Person:
    def __init__(self, fname, lname):
        self.firstname = fname
        self.lastname = lname

    def printname(self):
        print(self.firstname, self.lastname)

# Taban sınıf örneği:
p = Person("John", "Doe")
p.printname()  # Çıktı: John Doe

# Student sınıfı; Person'dan miras alıyor.
class Student(Person):
    pass

s = Student("Ali", "Veli")
s.printname()  # Çıktı: Ali Veli

Alt Sınıfta init() ve super() Kullanımı

Alt sınıfın init() metodunu yeniden tanımlarken, taban sınıfın özelliklerini kaybetmemek için init() metodunu çağırmalıyız.

Doğrudan Taban Sınıf Çağrısı

class Student(Person):
    def __init__(self, fname, lname, year):
        Person.__init__(self, fname, lname)  # Taban sınıfın __init__() çağrılıyor.
        self.graduationyear = year

s = Student("Ali", "Veli", 2023)
s.printname()          # Çıktı: Ali Veli
print(s.graduationyear)  # Çıktı: 2023

super() Fonksiyonu ile init() Kullanımı

Alt sınıfın ebeveyninden tüm metotları ve nitelikleri miras almasını sağlayacak bir super() işlevine de sahiptir:

class Student(Person):
    def __init__(self, fname, lname, year):
        super().__init__(fname, lname)
        self.graduationyear = year

s = Student("Ali", "Veli", 2023)
s.printname()          # Çıktı: Ali Veli
print(s.graduationyear)  # Çıktı: 2023

super() işlevini kullanarak, taban sınıfın adını kullanmak zorunda kalmazsınız. Metotlar ve nitelikler otomatik olarak ebeveynden devralır.

İleri Seviye: *args ve **kwargs Kullanımı

Parametre listesini tekrardan yazmaktan kaçınmak için:

class Student(Person):
    def __init__(self, *args, year, **kwargs):
        super().__init__(*args, **kwargs)
        self.graduationyear = year

s = Student("Ali", "Veli", year=2023)
s.printname()          # Çıktı: Ali Veli
print(s.graduationyear)  # Çıktı: 2023

Method Overriding (Metot Ezme)

Method overriding, alt sınıfın, taban sınıfta tanımlı bir metodu aynı isimle yeniden tanımlayarak, kendi davranışını oluşturmasıdır.

Alt sınıf nesnesi için aynı isimli metot çağrıldığında, taban sınıfın metodu yerine alt sınıfta tanımlanan metot çalışır.

Örnek:

class Person:
    def greet(self):
        print("Hello")

class Student(Person):
    def greet(self):
        print("Hi, I'm a student!")

s = Student()
s.greet()  # Çıktı: Hi, I'm a student!

Gelişmiş Örnek: Oyuncu, Asker, İşçi ve Yönetici

Taban Sınıf: Oyuncu

class Oyuncu:
    def __init__(self, isim, rütbe):
        self.isim = isim
        self.rütbe = rütbe
        self.güç = 0

    def hareket_et(self):
        print('hareket ediliyor...')

    def puan_kazan(self):
        print('puan kazanıldı')

    def puan_kaybet(self):
        print('puan kaybedildi')

Alt Sınıflar: Özel Güç Değerleri

Her alt sınıf, taban sınıfın init() metodunu super() ile çağırarak kendi güç değerini belirler.

class Asker(Oyuncu):
    def __init__(self, isim, rütbe):
        super().__init__(isim, rütbe)
        self.güç = 100

    def hareket_et(self):
        super().hareket_et()
        print('hedefe ulaşıldı.')

class İşçi(Oyuncu):
    def __init__(self, isim, rütbe):
        super().__init__(isim, rütbe)
        self.güç = 70

class Yönetici(Oyuncu):
    def __init__(self, isim, rütbe):
        super().__init__(isim, rütbe)
        self.güç = 50

Kullanım:

asker = Asker('Ahmet', 'Binbaşı')
işçi = İşçi('Mehmet', 'Usta')
yönetici = Yönetici('Selim', 'Müdür')

print(asker.isim, asker.rütbe, asker.güç)  # Çıktı: Ahmet Binbaşı 100
asker.hareket_et()                        # Çıktı: hareket ediliyor...
                                          #         hedefe ulaşıldı.
işçi.puan_kaybet()                        # Çıktı: puan kaybedildi
yönetici.puan_kazan()                     # Çıktı: puan kazanıldı

Çoklu Miras (Multiple Inheritance) ve MRO

Python’da bir sınıf birden fazla sınıftan miras alabilir. Bu durumda, Method Resolution Order (MRO), bir nesnenin metotlarını veya niteliklerini ararken hangi sırayla hangi sınıflara bakılacağını belirler.

MRO (Method Resolution Order) Tanımı

  • Tanım: MRO, Python’ın bir nesnede aranan metot ya da nitelik için, çoklu miras durumunda hangi sınıfın hangi sırayla kontrol edileceğini belirleyen kurallar bütünüdür.
  • Python, her sınıf için mro adında bir liste oluşturur. Bu liste, metot arama sırasını soldan sağa doğru gösterir.

Örnek: Car, Flyable ve FlyingCar

class Car:
    def start(self):
        print('Start the Car')
    def go(self):
        print('Going')

class Flyable:
    def start(self):
        print('Start the Flyable object')
    def fly(self):
        print('Flying')

class FlyingCar(Flyable, Car):
    def start(self):
        # MRO'ya göre ilk bulunan start() metodu çağrılır.
        super().start()

Kullanım

if __name__ == '__main__':
    fc = FlyingCar()
    fc.go()    # Car'dan: "Going"
    fc.fly()   # Flyable'dan: "Flying"
    fc.start() # Çıktı: "Start the Flyable object"

MRO’nun İncelenmesi

print(FlyingCar.__mro__)
# Örnek çıktı:
# (<class '__main__.FlyingCar'>, <class '__main__.Flyable'>, <class '__main__.Car'>, <class 'object'>)

Miras Alma Türleri

Miras alma sürecinde üç senaryo görülebilir:

  1. Olduğu Gibi Aktarma: Alt sınıf hiçbir ekleme yapmadan pass kullanır.

  2. Yeniden Tanımlama (Overriding): Alt sınıf, taban sınıftaki metodu kendine göre yeniden yazar.

    class Asker(Oyuncu):
        def hareket_et(self):
            print('yeni hareket_et() metodu')
  3. Yeni Nitelik ve Metot Eklemek: Alt sınıfa ek özellikler eklenir (örneğin, memleket gibi).

    class Asker(Oyuncu):
        memleket = 'Arpaçbahşiş'

Eğer alt sınıfta, taban sınıfta tanımlı bir nitelik veya metot yeniden tanımlanırsa, alt sınıftakiler geçerli olur.

Diğer super() Kullanım Alanları

super() fonksiyonunu yalnızca init() içinde değil, diğer metotlar içinde de kullanabilirsiniz. Böylece taban sınıfın metotları üzerinde ek işlevsellik katabilirsiniz.

class Asker(Oyuncu):
    def hareket_et(self):
        super().hareket_et()  # Taban sınıfın hareket_et() metodu çağrılır.
        print('hedefe ulaşıldı.')

Uygulama Alanları: Grafik Arayüz Tasarlama

  • Kalıtım, sadece komut satırı uygulamalarında değil, grafik arayüz tasarımında da yoğun şekilde kullanılır.
  • GUI kütüphaneleri (Tkinter, PyQt, wxPython vb.) nesne yönelimli yapıları temel alır.
  • Taban sınıflardan türeyen alt sınıflarla, buton, menü, diyalog kutusu gibi öğelerin davranışları kolayca genişletilebilir.

Alıştırma Soruları

  • Soru 1: Person adlı bir taban sınıf oluşturun. Bu sınıfın printname() metodu ve isim, soyisim nitelikleri olsun. Ardından, Teacher adlı bir alt sınıf türeterek, printname() metodunu ezip ek olarak öğretmenin branşını da ekrana yazdırın.
  • Soru 2: Vehicle adında bir taban sınıf oluşturun. Bu sınıfta start() metodu tanımlayın. Ardından, Car ve Boat adında iki alt sınıf türeterek, her biri için start() metodunu kendine has şekilde ezip, her iki sınıfı da miras alan AmphibiousVehicle adlı bir sınıf oluşturun.
    • MRO’yu inceleyin ve super() kullanarak hangi metodun çağrıldığını kontrol edin.
  • Soru 3: Oyuncu örneğini genişleterek; Player adlı bir taban sınıf oluşturun. Ardından, Warrior, Mage ve Archer adında alt sınıflar tanımlayın.
    • Her alt sınıfın güç değerini farklı yapacak şekilde init() metodunu yeniden tanımlayın.
    • Her sınıfa özgü ek metotlar ekleyerek, oyuncuların farklı yeteneklerini modelleyin.

Sonuç

  • Kalıtım, kod tekrarını azaltır ve modüler, bakımı kolay sistemler oluşturmayı sağlar.
  • init() ve super() ile taban sınıfın özellikleri korunurken, alt sınıflar özgün davranış ekleyebilir.
  • Çoklu miras ve MRO, karmaşık durumların üstesinden gelmek için önemli araçlardır.
  • Grafik arayüz programlama gibi ileri uygulama alanları, kalıtımın gücünü ortaya koyar.

Soru & Cevap

  • Sorularınız? Python’da nesne yönelimli programlamanın inceliklerini tartışmaya açığız.