Bu bölümde "Inheritence" yani "Kalıtım/Miras" konusunu göreceğiz. Bu konu oldukça mühim bir konudur ve bize inanılmaz bir kolaylık sağlıyor. Inheritence sayesinde tanımladığımız ana class yapısıyla bağlantılı alt class yapıları yaratabiliyoruz.
Örneğin ana class yapımız class Çalışan: olsun ve içerisinde çalışanlara ait özellikler olsun. Bu class dışında başka bir alt class daha oluşturursak ve ana class yapımızdan yani Çalışan sınıfından miras alırsak alt class içerisinden ana class içerisinde bulunan özelliklere erişebiliriz.
Bunu bu şekilde anlaması biraz zor olabilir. O yüzden yavaştan başlayalım.

class Employee: şeklinde, çalışanları temsil eden bir sınıf oluşturdum ve içerisine __init__ metodu içerisinde isim, soyisim, maaş özelliklerini tanımladım. Sonrasında zaten bildiğiniz gibi self.firstName = firstName şeklinde bunları tanımladım.
Bu noktada 9. satıra bakarsanız değişik bir şey yaptığımı göreceksiniz. Çalışanların mail adreslerini (contact), __init__ içerisine vermeden direkt olarak tanımladım. Bu, yapılabilir bir şeydir. Eğer bunu __init__ içerisine verseydiniz self.contact = contact demek zorunda kalırsınız ve bu tanımlamayı sonradan yapmanız gerekecektir.
Ayrıca employee1 nesnesini tanımlarken contact bilgisi de girmedim. Bunun sebebi, bu bilginin __init__ içerisinde olmamasıdır. Daha doğrusu bunun, __init__ argümanları içerisinde olmamasıdır. Ben bu bilgiyi direkt olarak self.contact diyerek tanımladım ve değerini verdim.
Bu kodu çalıştırıp ne olacağına bakalım.

Gördüğünüz üzere __init__ içerisindeki özelliklere de contact bilgisine de erişebiliyorum. Ancak bir sorun var; bir mail adresinde büyük harf olmamalı. Bunu nasıl düzeltebilirsiniz? Devam etmeden önce bunu yapmayı deneyin.

String Metotları blogundan hatırlayacağınız üzere lower() fonksiyonunu kullandık ve normal bir mail adresine dönüştürdük.
Şimdi, asıl konumuza dönelim. Burada biz, genel olarak bir "Çalışan Sınıfı" yaratmış olduk. Büyük ölçekli bir işletme düşünelim. Bu işletmelerde 3 adet yönetici sınıfı vardır. Bunlar sırasıyla yukarıdan aşağı olacak şekilde, 'üst düzey yöneticiler', 'orta düzey yöneticiler' ve 'alt kademe (operasyonel) yöneticiler' şeklindedir. Bu insanların ne yaptığını bilmenize gerek yok sadece üç adet sınıfımız olduğunu bilin yeter. Şimdi, bu sınıflardan üst düzey yöneticilerine hitap eden bir class oluşturalım.

class TopManager(Employee): dedik. Değişik bir yapı, değil mi? Normalde metot tanımlarken parantez içerisine verdiğimiz self parametresi bir referans idi. Burada da aynı şekilde düşünebilirsiniz. Biz, TopManagers isimli sınıfa Employee isimli sınıfı referans verdik. Bu noktada olan şey tam olarak "Inheritence - Kalıtım/Miras" olayıdır. Bunu yaptığımız zaman TopManagers class yapısı içerisinden, Employee class yapısındaki özelliklere erişebiliyor olmamız lazım. Bakalım.

topEmployee = TopManagers(...) derken aslında TopManagers isimli class için bir nesne oluşturdum, öyle değil mi? Ancak TopManagers sınıfı içerisinde ne bir __init__ metodu ne de başka bir metot mevcut; yalnızca pass komutu var. Buna rağmen biz, Inheritence yapısını kullandığımız için TopManagers isimli sınıfa ait bir nesne için Employee isimli sınıf üzerinden özellik çekebiliyoruz. Bence bu harika bir mimari.
Bu durum bu noktada size saçma gelebilir. Ancak dikkat edelim; bizim yalnızca bir tane alt sınıfımız var ve birazdan iki tane daha oluşturacağız. Her sınıf yöneticiyi sadece tek bir class içerisinde tutarsak kodumuz tabiri caizse arap saçına dönecektir.
Şimdi, bu kodu çalıştırıp ne olacağına bakalım.

Bence çok güzel oldu. Şimdi, diğer sınıflara geçmeden önce class değişkenleri üzerine biraz konuşalım.

class değişkenlerinin ne olduğunu önceki yazılardan biliyorsunuz. Bu noktada iki farklı sınıfa da orada kaç kişi çalıştığını tanımladım ve iki değeri de çekebildim. Demek ki bunlar iki farklı yapı ama Inheritence sayesinde birbirlerinden miras alabiliyorlar. Diyelim ki bir çalışan, işletmede genel olarak kaç çalışan olduğunu bulmak istiyor; ona göre bir sorgu yaptırabilirsiniz. Diyelim ki yeni biri işe alındı, ona göre bir çalışan ekleme metodu belirler, employeeCounter değerini artırırsınız. Bunun gibi birçok şeyi yapabilirsiniz.
Şimdi, başka sınıflar tanımlayalım.

Gördüğünüz üzere 3 farklı yönetici sınıfını tek bir çatı altında topladık. Bu noktada istediğiniz sınıfa istediğiniz özellikleri verebilirsiniz. Örneğin işletmede her sene başında zam yapılıyor olsun. Üst kademe ile alt kademe yöneticilerin alacağı zam oranı birbirinden farklı olacaktır, değil mi? İşte, bu gibi spesifik özellikleri ait olduğu sınıfa tanımlayabilirsiniz. Ancak genel özellikler tek bir çatı altındadır. Zaten class yapısının da mantığı budur; OOP | Bölüm 1 isimli yazıdan kısa bir hatırlatıcı:

Şimdi, yönetici sınıflarını tanımladık. İşletmelerde bir de "operasyonel çalışanlar" vardır. Bunlar, operasyonel (alt kademe) yöneticilere bağlıdırlar. Elbette, genel olarak birden fazla yönetim şekli vardır; konumuz bu değil ama bu noktada biz, emir-komuta zincirinin yukarıdan aşağı doğru olduğunu varsayıyoruz. Üst kademenin verdiği karar alt kademeye kadar ulaşır ve alt kademe, operasyonel çalışanlara bu işleri yaptırır. Tam olarak bu noktada, bu mantığa göre dilerseniz class MidManagers(Employee) demek yerine class MidManagers(TopManagers) diyebilirsiniz. Aynı zamanda class LowManagers(Employee) demek yerine class LowManagers(MidManagers) diyebilirsiniz.
O zaman biz, bu operasyonel çalışanlar için de bir sınıf oluşturursak Inheritence mantığına göre hangi sınıftan miras alır?

Gördüğünüz üzere bu sınıf, Employee sınıfı yerine LowManagers sınıfını referans olarak alıyor. Peki, böyle bir şey mümkün mü?
Örneğin yine OperationEmployees isimli sınıf için bir instance oluşturalım.

OperationalEmployees isimli sınıftan bir instance oluşturduk. OperationalEmployees sınıfı LowManagers sınıfıyla çalışmasına rağmen ana sınıfımız olan Employee sınıfından özellik çekebiliyor. İşte Inheritence yapısının güzelliği burada. Bunu size bir şema ile göstereceğim.

Yukarıdaki şema, bizim biraz önce kodlara döktüğümüz yapıyı gösteriyor. Yeşil oklara dikkat ederseniz bunların birbirine bağlı olduğunu görürsünüz. Yani Orta Kademe Yöneticiler (MidManagers) Çalışan (Emplooye) sınıfına bağlı. Aynı zamanda Operasyonel Çalışanlar (OperationalEmployees) Orta Kademe Çalışan (MidManagers) sınıfına bağlıdır. Dolayısıyla bunlar arasında bir korelasyon mevcut ve bunlar birbirini tanıyor. Bunu dede-baba-çocuk ilişkisi gibi düşünebilirsiniz.
Yani biz, Operasyonel Çalışanlar (OperationalEmployees) içerisinden sorgu yaparken aslında aşağıdaki gibi bir durum söz konusu oluyor.

Dilerseniz az önce oluşturduğumuz sınıfların içerisini de doldurabilirsiniz. Orası tamamen size kalmış. Örneğin yönetici kadroyu bir sınıf değişkeni olarak tanımlayalım.

Şu şekilde bir kullanım da sağlamak mümkün. Ancak pek verimli ve esnek olduğu söylenemez. Bunun yerine şimdi başka bir yöntem kullanacağız.
Normalde __init__ ve self ile nesneleri kontrol altına alabiliyorduk. O zaman TopManagers sınıfına bir __init__ tanımlarsak CEO, COO, CTO gibi unvanları/pozisyonları buraya tanımlayabiliriz. Bakalım.

Employee sınıfında yaptığımız gibi TopManager sınıfı için bir __init__ tanımladık ve her şeyi tekrar yapmış gibi olduk. Buradaki tek fark, status özelliğidir. status özelliğini eklemek istedim. Ancak burada büyük bir sorun var; kod tekrarı. Çok fazla kod tekrarı yaptığımız için bir süre sonra her şey karmakarışık olacaktır. İşte, bu tanımlamanın kısa yolunu göstereceğim.
OOP yapısında miras alınan sınıf (Employee) yani ana sınıfın diğer adı super şeklindedir. Bu bilgiyi zihnimize alalım.

def __init__() dedikten sonra eski parametreleri de alıyoruz ve eklemek istediğimiz başka bir özellik varsa onu ekliyoruz (status). Sonrasında super().__init__() diyoruz ve super class hangisi ise yani hangi sınıftan miras alıyorsak oradaki __init__ içerisinde yazanları alıyoruz. Bu sayede tekrardan self.firstName = firstName demek zorunda kalmıyoruz.
Yani super().__init__(firstName, lastName, salary) derken aslında şunu diyoruz: "super sınıfından (miras alınan sınıf; Empolyee) bu üç özelliği al."
Sonrasında yapmamız gereken tek şey, tanımladığımız yeni özelliği self diyerek tanımlamaktır; self.status = status.
Şimdi, sadece status bilgisini döndüren bir metot yazalım ve yöneticilerimizi instance olarak tanımlayalım.

Normalde aşağıdaki gibi bir tanımlama yapıyorduk;
topManagerCEO = TopManagers("X", "X", 42000, "CEO")
Ancak yukarıda, biraz daha farklı bir tanımlama görüyorsunuz. Burada her özelliği, ait olduğu değişkeni yazarak tanımlıyorum:
topManagerCEO = TopManagers(firstName="X", lastName="X", salary=42000, status="CEO")
Yani bu şekilde bir tanımlama da mümkün. Elimden geldiğince yeni şeyleri göstermeye çalışıyorum. Size hangisi hitap ediyorsa onu kullanabilirsiniz.
Sonrasında metotları çağırarak topManagersCEO için çalıştırıyoruz. Çıktımıza bakalım.

Elbette, eğer isterseniz diğer nesneleri de yazdırabilirsiniz.

Şimdi, iki önemli fonksiyon göstermem gerekiyor. Bunlar sırasıyla 'isinstance()' ve 'issubclass()'.
isinstance() fonksiyonu iki argüman alıyor. Bunlardan ilki instance yani nesne, ikincisi ise class. Bu fonksiyona verdiğiniz instance, verdiğiniz class'a ait mi diye kontrol ediyor. Eğer instance o class'a aitse True, değilse False değer dönecektir. Bakalım.

Burada, opEmployee1 isimli nesnenin, OperationalEmployees isimli class'a ait olup olmadığını sorguladık ve sonuç True geldi. Gerçekten de OperationalEmployees sınıfına ait bir instance.

42. satırda gördüğünüz üzere opEmployee1 nesnesinin TopManagers class'ına ait olup olmadığını sorguladık ve ait olmadığı için False değer döndü.
issubclass() fonksiyonu da iki argüman alıyor ama bu argümanların ikisi de class olmalıdır. Bu fonksiyon, verdiğiniz ilk class ikinci class'ın alt class'ı mı diye bakıyor.

41. satırda LowManagers sınıfının OperationalEmployees sınıfının bir alt sınıfı olup olmadığını sorguladık ve False değer döndü. Çünkü aslında OperationalEmployees sınıfı LowManagers sınıfının bir alt sınıfı konumunda. Zaten 42. satırda bunu görüyorsunuz; sonu. True şeklinde.
Bir sonraki bölümde görüşmek üzere.
Yayınlanma Tarihi: 2022-12-24 13:46:07
Son Düzenleme Tarihi: 2022-12-29 13:38:39