Bir niteliğin `super()` ile değil de `self` ile tanımlanmasının nedeni

class Page(Content):
def init(self,title,body,date):
super().init(title,body)
self.date = date
def show(self):
return “%s \ntarih: %s” % (super().show(),self.date)
pass

Burada neden date yi self ile tanımlamış da super metodunun içine yazmamış. Üstelik self.date olarak değil de super().init(title,body,date) olarak yazınca kod çalışmıyor. Saçma bir soru olabilir ama aklıma takıldığı için sormak durumundayım. (bu arada nasıl kod satırı paylaşıyorsunuz? ben direk buraya yazıyorum. onu söylerseniz sevinirim)

yazıyı yazdığınız kısımda </> simgesi yada Ctrl+E ye basarsanız kodu buraya gir veya yapıştır çıkıyor oraya yapıştırın kodunuzu

Şöyle örnek olarak bir kod bırakıyorum:

class HomoSapiens:
    def __init__(self,isim):
        self.isim = isim # "self.<rastgele_değişken_ismi> = parametre"

        if self.yürüyebilen():
            print(f"{self.isim} isminde özel karakter olduğundan bu kişi yürüyemez")
        else:
            print("İşte gerçek bir insan")

    def yürüyebilen(self):
        durum = False
        for i in "><£#$½{[]}\\":
            if i in self.isim:
                durum = True
            else:
                durum
        return durum

class ModernInsan(HomoSapiens):
    def __init__(self, isim):
        self.isim = isim
        super().__init__(isim)

ModernInsan("Arif")
ModernInsan("A[]rif><")
Çıktı

İşte gerçek bir insan
A[]rif>< isminde özel karakter olduğundan bu kişi yürüyemez

Burada HomoSapiens sınıfı oluşturdum.
ModernInsan sınıfında kullandığımız gibi bir kalıtım yaparak kullanacaksak o bilinçle ebeveyn sınıfı yazılıyor.
Yazılan bu sınıfta __init__() methodu, yazılan sınıf en alttaki gibi çağrılıp belirlenen parametre verildiğinde ilk olarak çalışan method oluyor.
ilk parametre “self” olmak zorunda değil, ama ilk parametre her zaman belirlenen “bir şey” olmak zorunda. ilk parametre kullanılarak oluşturulan değişkenler diğer bir adı ile, sınıfta türetilen nesneler, diğer methodlar tarafından da erişilebilmesi adına belirlediğimiz parametre ile yazılarak değişken/alan(field) oluşturuluyor. Farkındaysanız HomoSapiens sınıfının __init__ methodunda yer alan isim parametresini, self kullanarak parametrenin taşıdığı ismin aynısını veriyorum. Burada farklılık olabilir elbette. Ama kafa karışıklığını gidermek adına türetilen nesne ismi ile __init__ methoduna verilen parametre isimleri genelde aynı oluyor.

ModernInsan sınfında ise göreceksiniz ki HomoSapiens sınıfını miras almış.
Bu demek oluyor ki miras sınıfna ait olan kullanılmak üzere oluşturulmuş olan bütün methodlara
ModernInsan sınıfı içerisinde ulaşabiliyoruz.
Gördüğünüz üzere ModernInsan sınıfının __init__ metoduda bir isim adında parametre alıyor.
aynı parametreyi (yine sınıf içerisinde kullanacağımı düşündüğümden) self anahtar kelimesi ile türetip bunu __init__ methodundaki isim parametresine atıyorum.

Peki bu atanan değişkeni ebeveyn sınıfta nasıl kullanıcam?
Burada da şöyle bir olay gerçekleşiyor:
super() adıyla bilinen sınıf, Ebeveyn olarak kullandığımız sınıfın ta kendisi olmuş oluyor.
yani ben diyorum ki burada “HomoSapiens sınıfının __init__ methoduna, ModernInsan sınıfında oluşturulan __init__ metodunun isim adlı parametresinin aldığı arguman(girilen veri/değer) kullanılsın”

Dilim döndüğünce bilgim yettiğince bilgimi aktarmaya çalıştım. Umarım anlaşılmıştır.

1 Beğeni

bu Çıktı yazısını, dün de Kod yazısı vardı tıklayınca açılıp kodlar gözüküyordu onu nasıl yapıyoruz.

Yanıt yazarken çarka tıklayıp detayları gizle dediğinizde yapabiliyorsunuz.

1 Beğeni
Tamam

Teşekkürler değişik şeyler öğrenmek güzel

2 Beğeni

class Page(Content) yazdığınızda inheritance (kalıtım) gereği, Content sınıfı, Page sınıfının parent sınıfı (ebeveyn) oluyor. Inheritance, benzer özellikler taşıyan ve “is-a” ilişkisini sağlayan (“Page is a Content”) sınıfları birbirine bağlayarak kod tekrarını ortadan kaldırır. Yani yukarıdan, parent’dan ne var ne yok (attribute (nitelik), metot) miras edinirsiniz (inherit).

Ama olay burada bitmiyor tabii; Content’teki her şeyi miras alıp başka bir şey yapmayacaksak neden yeni bir sınıf (Page) yazıyoruz? Dolayısıyla alt sınıfın, üst sınıftan aldıklarının yanında masaya koyacağı başka şeyler de olmalıdır. Sizin örneğinizde bunu date niteliği ile görüyoruz. Onu super’e yollamayıp self. ile ilklendirmenizden şunu anlıyoruz: Content nesneleri normalde date’e sahip değildir, ama aradığımız, ortak olarak paylaşmak istediğimiz birçok şeye sahiptir (title, body). O zaman bu ortak olanları onun sayesinde ilklendirip kendi niteliğimiz yapalım, bu farklı olanı (yani date’i, yani bu yeni sınıfı yazma dürtülerimizden biri olan niteliği) kendimiz alt sınıftaki __init__'in içerisinde self.date = ... diye halledelim.

Alt sınıfın metotlar üzerine de koyacağı şeyler olabilir. Önce üzerine koymak istemeyeceği, direkt miras alacağı, kod tekrarından kaçınmayı sağlayacağı bir örnekten başlayalım. Mesela başlık ve body’deki toplam karakter sayısını merak ediyoruz. Üst sınıf Content sınıfı şöyle bir metoda sahip:

# Content sınıfının içerisindeyiz
def karakter_sayisi(self):
    return len(self.title + self.body)

Bu metodun üzerine alt sınıf Page’in katacağı bir şey yok; bu metodu tekrar Page sınıfında bir daha yazmayız. Content “olan” (Page “is a” Content) her “şey” (buradan polymorphism’e yelken açarsınız) bu metodu miras edip direkt kullanır.

Şimdi ise alt sınıfın, üstte bulunmayan ve kendine has niteliklerini kullanan bir metodunu yazarak masaya yeni bir şey koyalım (tekrar: yeni bir (alt) sınıf yazmamızın dürtülerinden birisi). Mesela bir Page nesnesinin oluşturulma tarihinin (.date) üzerinden kaç gün geçtiğini merak ediyoruz. Content sınıfında böyle bir metot yok, olamaz: genelgeçer Content objelerinin .date diye bir niteliği yok zira. Page sınıfında biz kendimiz yazarız bu metodu, miras almayız, üst sınıfı “extend” ederiz:

# Page sınıfının içerisindeyiz
def kac_zaman_oldu(self):
    return datetime.datetime.now() - self.date

Bu artık her Content objesinde bulunmaz, Page (ve Page’den inherit edenlerin!) objelerinde bulunur.

Bir diğer durum da, halihazırda Content sınıfında bulunan bir metodun Page sınıfından (iyi nedenlerden dolayı :p) tekrar yazılmasıdır, override edilmesidir. Bunu mesela __str__ üzerinden görebiliriz. __str__ metodu bir objenin insan-okuyabilir temsilini döndürmeye yarayabilir. Content sınıfında bunun bir örneği şöyle olabilir:

# Content sınıfının içerisindeyiz
def __str__(self):
    return f"{self.title}\n{'*' * 40}\n{self.body}\nSON"

Her Contentte title ve body vardı ya, bu da onları kullanarak bir string temsili oluşturuyor Content nesneleri için. Ama Page nesneleri bununla yetinmeyip kendilerine has .date niteliğini de kullanmak isteyebilirler. Üstteki temsilin önünde tarih de yazsın. O zaman:

# Page sınıfının içerisindeyiz
def __str__(self):
    content_str = super().__str__()
    return f"Tarih = {self.date}\n{content_str}"

Burada Content’in __str__'sinin sağladığını önce elde ediyoruz, sonra .date’i işin içine katıp geriye bir string döndürüyoruz. Hem Content’te hem de Page’de artık __str__ metodu var. Eğer Page objesi __str__ metodunu çağırırsa (mesela str(Page(...)) ile), ona has olan çalışacaktır “override” ettiğimiz için. Ama düz bir Content objesi (veya Content’i parent belleyip de bu metodu override etmeyen bir sınıfın objesi) üzerinden __str__ çağrılırsa, Content sınıfındaki __str__ çalışır.

Velhasıl, bir sınıf, bir başka sınıfı miras aldığında, o sınıfın tüm fonksiyonalitesine erişebildiği gibi bunların üzerine de koyabiliyor (extend edebiliyor); daha doğrusu üstüne koyması bekleniyor, öbür türlü inheritance’a gerek yoktur. Aslında bu miras alan sınıfa, sizdeki Page, alt sınıf yerine belki üst sınıf (super class) desek daha doğru olabilir (ama terminoloji ekseriyetle öbür yönde); çünkü parent’in sağladığının üzerine çıkıyor, boynuz kulağı geçmiş oluyor. “Hepsi ve daha fazlası” diyebiliriz… (Ebeveyn sınıfın halka açık olarak (public) sunduğu tüm fonksiyonaliteye erişebiliyor, özel olanlara (private) programlama diline bağlı olarak erişemeyebilir; Python’da private nitelik/metot olmadığından ne var ne yok erişilebiliyor.)

4 Beğeni

Kim?

super bir method degil, super sinifin (Content) __init__ metodundan mi bahsediyoruz?

Eger oyleyse: date’in Page’de olmasini istemis de Content’te olmasini istememis.

Demek ki Content.__init__, date parametresi almiyor.

bkz: Soru Sorarken Sıkça Düşülen Hatalar #1

3 Beğeni