Python nesne tabanlı bir programlama dilidir. Günümüz modern programlama dillerinin hemen hemen hepsinin nesne tabanlı olmasından, nesneye dayalı programlamanın ne kadar önemli bir konsept olduğu açıkça anlaşılıyor.

Python’da hemen hemen her şey bir nesnedir. Bu nesnelerin özellikleri ve metodları vardır. Bir sınıf ise basitçe ifade etmek gerekirse, nesnenin oluşturulmasını sağlayan şablondur.

Javascript’in Temelleri başlığı altında nesneleri bir örnekle incelemiştik. Göz atmak isterseniz, her dilde ortak bir konsept olduğunu göreceksiniz.

Python’da bir sınıf oluşturmak için class anahtar kelimesiyle büyük harfle başlayan bir isim vermek yeterlidir;

class IlkSinif:
     ozellik1 = "Sınıfın ilk özelliği."

Sadece bu sınıfın adını kullanarak bu sınıftan bir nesne oluşturabiliriz;

yeniNesnem=IlkSinif()

Artık bu nesne yardımıyla sınıfın özelliklerini nokta . notasyonu ile kullanabiliriz;

class IlkSinif:
  ozellik1="Sınıfın ilk özelliği bu metin olsun"

yeniNesnem=ilkSinif()

print(yeniNesnem.ozellik1)

Çıktı:

Sınıfın ilk özelliği bu metin olsun

 

Gördüğünüz gibi bir sınıftan oluşturulan her nesne sınıfın özelliklerini taşıyan bir örneğidir.

 

__init__() Fonksiyonu

Basit bir örnek ile sınıf kavramına ve onların örneklemesi olan nesnelere giriş yaptık. Ancak sınıfları daha iyi anlayabilmek için Python’ın dahili fonksiyonlarından biri olan __init__() fonksiyonunu tanımak gerekir. Tüm sınıflar __init__() fonksiyonuna sahiptir. Bu fonksiyon sınıf başlatılırken çalıştırılan ilk fonksiyondur. Nesne özelliklerine değer atamak ya da nesne oluşturulurken yapılması gereken diğer işlemleri gerçekleştirmek için __init__() fonksiyonu kullanılır.

Sınıftan yeni bir nesne oluşturulduğunda __init__() fonksiyonu otomatik olarak çalıştırılır. Dolayısıyla burada, nesnelerin taşımasını istediğimiz özelliklerini yerleştirir ve nesne tanımlandığında çalıştırılmasını istediğimiz fonksiyonlara çağrı yaparız.

__init__() fonksiyonunun ilk parametresi temsili olarak nesneyi ifade eder ve genellikle sabit olarak self kelimesi ile ifade edilir. Bu kelime ayrıca o fonksiyon içindeki her bir özelliğin de başına eklenerek bu özelliğe sınıf içinde her yerden erişilebilmesini sağlar.

Ancak self kullanmak zorunlu değildir. O nedenle ben buradaki örneklerde ve kendi kodlarımda oluşturduğum sınıf ile daha alakalı bir kelime bulup kullanmayı tercih ediyorum. Siz geleneksel olarak self kullanmayı tercih edebilir, örneğin “nesne” gibi farklı bir kelime belirleyebilir ya da benim izlediğim yolu kullanarak her sınıf için farklı bir anlamlı kelime kullanabilirsiniz.

Şimdi örnek bir personel sınıfı oluşturmak için bu fonksiyonu kullanalım;

class Personel:
  def __init__(kisi,ad,soyad, programlamaDili, deneyimSuresi):
    kisi.ad=ad
    kisi.soyad=soyad
    kisi.programlamaDili=programlamaDili
    kisi.deneyimSuresi=deneyimSuresi

 

Artık programımızı yazarken bu sınıftan bir nesne oluşturup, o nesnenin özelliklerini belirtip kullanabiliriz;

personel1 = Personel("Oben","Seven",("Python","PHP","Javascript"),18)
print("Personel Ad-Soyad: " + personel1.ad + " " + personel1.soyad)
print("Deneyim Süresi: " , personel1.deneyimSuresi)
print("Kullandığı Programlama Dilleri: " , personel1.programlamaDili)

Çıktı:

Personel Ad-Soyad: Oben Seven
Deneyim Süresi: 18
Kullandığı Programlama Dilleri: ('Python', 'PHP', 'Javascript')

Burada __init__() metodunun parametreleri ile metod içinde tanımlanan özellik(değişken) sayısının eşit olması şart değildir.  Dilerseniz her bir nesne için değeri sonradan değiştirilebilecek kisi.maas=0 gibi sabit başlangıç değerine sahip nesne özellikleri de tanımlayabilirsiniz. Bu özellikler nesne oluştururken parametre olarak kullanılmaz ama metodlar içinde kullanılarak değiştirilebilir.

 

Sınıf içinde 2 farklı şekilde özellik tanımlayabiliyoruz. Eğer konunun başındaki ilk örneğimizde olduğu gibi tanımlarsak bu özelliğin değeri o sınıftan üretilecek olan her bir nesnede aynı olur. Bu özellikler Sınıf Özellikleri adını alır. __init__() fonksiyonu içinde tanımlanan özelliklerin değeri ise o sınıftan üretilen nesnelerde farklı değerlere sahip olur. Bu özelliklerde Nesne Özellikleri adını alır;

 

class Personel:
  departman = "Yazılım"
  def __init__(kisi,ad,soyad, programlamaDili, deneyimSuresi):
    kisi.ad=ad
    kisi.soyad=soyad
    kisi.programlamaDili=programlamaDili
    kisi.deneyimSuresi=deneyimSuresi

Şimdi Personel sınıfımızdan oluşturduğumuz her nesne için departman değişkeninin değeri aynı olacaktır;

personel1 = Personel("Oben","Seven",("Python","PHP","Javascript"),18) 
print("Personel Ad-Soyad: " + personel1.ad + " " + personel1.soyad) 
print("Deneyim Süresi: " , personel1.deneyimSuresi) 
print("Kullandığı Programlama Dilleri: " , personel1.programlamaDili)
print("Çalıştığı Bölüm: ", personel1.departman)
print()
personel2 = Personel("Mert", "Demir", ("ReactJS","Python"),5)
print("Personel Ad-Soyad: " + personel2.ad + " " + personel2.soyad) 
print("Deneyim Süresi: " , personel2.deneyimSuresi) 
print("Kullandığı Programlama Dilleri: " , personel2.programlamaDili)
print("Çalıştığı Bölüm: ", personel2.departman)

Çıktı:

Personel Ad-Soyad: Oben Seven
Deneyim Süresi: 18
Kullandığı Programlama Dilleri: ('Python', 'PHP', 'Javascript')
Çalıştığı Bölüm: Yazılım

Personel Ad-Soyad: Mert Demir
Deneyim Süresi: 5 
Kullandığı Programlama Dilleri: ('ReactJS', 'Python')
Çalıştığı Bölüm: Yazılım

Tabii bu değişkenin değeri daha sonradan değiştirilebilir. Ancak sınıf özelliklerinin  sınıftan üretilen tüm nesneler için ortak değere sahip olacağını unutmayınız.

 

Nesne Metodları

Sınıflar içinde fonksiyonlar tanımlayabiliriz. Bu fonksiyonlar uygulamalarımızın içinde sınıftan oluşturulan nesneler üzerinde metodlar olarak kullanılabilirler.

Sınıf içinde fonksiyonlar oluştururken __init__() fonksiyonunda ilk parametre olarak  verdiğimiz parametreyi yine ilk parametre olarak kullanırsak, __init__() fonksiyonunun ve benzer şekilde oluşturulmuş diğer fonksiyonların içindeki değişkenlere de erişebiliriz. 

Şimdi örnek olması için Personel sınıfımız içinde kendi fonksiyonumuzu yazalım. Örneğimizde, personelin kullandığı birden fazla programlama dili olabilir. Eğer veri türü demet ya da liste ise bu birden fazla programlama dilini bir döngü ile ekrana yazdıran, eğer sadece tek bir veri mevcutsa ve veri türü string ise bunu ekrana yazdıran bir fonksiyon yazalım. Daha sonra nesnemizi kullanırken veriye ulaşmak için kullandığımız nokta notasyonunun yanı sıra fonksiyonumuzu da çalıştıralım;

class Personel:
  def __init__(kisi,ad,soyad, programlamaDili, deneyimSuresi):
    kisi.ad=ad
    kisi.soyad=soyad
    kisi.programlamaDili=programlamaDili
    kisi.deneyimSuresi=deneyimSuresi

  def dilYazdir(kisi):
    veriTuru=type(kisi.programlamaDili)
    if veriTuru is str:
      print("  - ", kisi.programlamaDili)
    elif veriTuru is tuple or list:
      for dil in kisi.programlamaDili:
        print("  - ", dil)
    else:
      print("Hatalı bir veri girişi yapılmış!")

personel2 = Personel("Mert","Demir",("NodeJS","ReactJS"),6)
print("Personel Ad-Soyad: " + personel2.ad + " " + personel2.soyad)
print("Deneyim Süresi: " , personel2.deneyimSuresi)
print("Kullandığı Programlama Dilleri: ")
personel2.dilYazdir()

print("")
print("-------------------------")
print("")

personel3 = Personel("Ceren","Toktay","Javascript", 4)
print("Personel Ad-Soyad: " + personel3.ad + " " + personel3.soyad)
print("Deneyim Süresi: " , personel3.deneyimSuresi)
print("Kullandığı Programlama Dilleri: ")
personel3.dilYazdir()

Çıktı:

Personel Ad-Soyad: Mert Demir
Deneyim Süresi: 6
Kullandığı Programlama Dilleri: 
- NodeJS
- ReactJS

-------------------------

Personel Ad-Soyad: Ceren Toktay
Deneyim Süresi: 4
Kullandığı Programlama Dilleri: 
- Javascript

 

Python’da büyük projelerde çalışırken genellikle sınıfların ve içindeki özellik ve metodların ayrı bir dosya içinde tanımlandığı, bu dosyanın modül olarak eklendiği dosya içinde de, nesnelerin ve değerlerinin oluşturularak işlemlerin gerçekleştirildiği uygulamalara sıkça rastlarsınız.

Sınıf Metodları

Sınıflar oluşturulduğunda __init__() metodu ile nesne özelliklerini tanımladığımız gibi her nesne için ortak olan sınıf özelliklerini de sınıfın etki alanında tanımlayabildiğimizi biliyoruz. Ayrıca nesneler üzerinde işlem yapabilmemizi sağlayan nesne metodlarını da __init__() fonksiyonunun ilk parametresini ortak kullanarak tanımlayabildiğimizi, böylece nesne özelliklerini(değişkenlerini) kullanabildiğimizi hemen yukarıdaki başlıkta gördük. Bunların dışında sınıf üzerinde işlem yapabilmemizi sağlayan sınıf metodları da mevcuttur.

Sınıf metodlarını tanımlayabilmek için yazdığımız metoddan önceki satıra @classmethod dekoratörünü(decorator) ekliyoruz. Dekoratörler temel olarak fonksiyonu alır ve yeni işlevsellikler ekleyerek yine fonksiyon olarak döndürür, ancak bunun detayı farklı bir başlık altında işlenecektir.

Sınıf metodlarına tıpkı nesne metodlarında olduğu gibi ilk parametre olarak genellikle cls olarak kullanılan bir parametre ekliyoruz. Bu parametrenin de mutlaka cls olması şart değildir, ama genel kullanım bu yöndedir.

Şimdi sınıf metodlarını örneklemek açısından yeni bir sınıf oluşturalım. Bu sınıfın bir e-ticaret projesine ait olduğunu varsayalım ve sipariş verileri yapısını __init__() metoduyla oluşturalım. Ayrıca nesne olarak tanımlanan verilen sipariş bilgilerini görüntüleyecek bir de nesne metodu ekleyelim;

class Siparis:
  def __init__(siparis, siparisNo, urunAdi, siparisAdedi, siparisTutari):
    siparis.siparisNo=siparisNo
    siparis.urunAdi=urunAdi
    siparis.siparisAdedi=siparisAdedi
    siparis.siparisTutari=siparisTutari

  def siparisGoruntule(siparis):
    print()
    print("Sipariş No: ", siparis.siparisNo)
    print("Sipariş Edilen Ürün: ", siparis.urunAdi)
    print("Satın Alınan Ürün Adedi: ", siparis.siparisAdedi)
    print("Sipariş Tutarı: ", siparis.siparisTutari)
    print("---------------------------------------------")
    print()

siparis1=Siparis(1,"Peppino Kurşun Kalem",12,42.50)
siparis2=Siparis(2,"Peppino Boya Kalemi",3,32.25)
siparis3=Siparis(3,"A4 Boy 120 Yapraklı Kareli Defter",2,20)

Siparis.siparisGoruntule(siparis1)

Çıktı:

Sipariş No: 1
Sipariş Edilen Ürün: Peppino Kurşun Kalem
Satın Alınan Ürün Adedi: 12
Sipariş Tutarı: 42.5
---------------------------------------------

Gördüğünüz gibi, daha önce edindiğimiz bilgiler ile bu sınıftan oluşturulan her bir sipariş nesnesi ile ilgili verileri bu metod yardımıyla ekranda görüntüleyebiliyoruz.

Ancak burada siparişleri oluşturan nesnelerin de kaydını tutmak istiyoruz. Yani gelen her bir siparişin kaydedildiği bir yapıyı veritabanı ya da dosyaya kaydetmeden yine uygulama içinde tutacak basit bir şekilde düşünelim. Böylece oluşturulan tüm siparişler istenildiğinde görüntülenebilir.

Bunun için siparisler isimli liste türünde bir sınıf değişkeni oluşturalım. Bu listeye oluşturulan nesneleri kaydedecek bir de metod yazalım;

class Siparis:
  siparisler=[]

  def __init__(siparis, siparisNo, urunAdi, siparisAdedi, siparisTutari):
    siparis.siparisNo=siparisNo
    siparis.urunAdi=urunAdi
    siparis.siparisAdedi=siparisAdedi
    siparis.siparisTutari=siparisTutari
    siparis.siparisKaydet()

  def siparisGoruntule(siparis):
    print()
    print("Sipariş No: ", siparis.siparisNo)
    print("Sipariş Edilen Ürün: ", siparis.urunAdi)
    print("Satın Alınan Ürün Adedi: ", siparis.siparisAdedi)
    print("Sipariş Tutarı: ", siparis.siparisTutari)
    print("---------------------------------------------")
    print()

  def siparisKaydet(siparis):
    Siparis.siparisler.append(siparis)
    print("{} numaralı sipariş sipariş defterine kaydedilmiştir.".format(siparis.siparisNo))

Burada önce siparisler isimli bir liste oluşturduk ve sonra bir nesne metodu oluşturduk ki nesneyi bu listeye liste türünün append() metodu yardımıyla eklesin. Ayrıca dikkat edilmesi gereken önemli bir nokta da; bu metodu çalıştıracak olan metod çağrısını __init__() metodu içine yerleştirdik ki, her bir nesne oluşturulduğunda __init() metodu çalıştırılacak ve dolayısıyla nesneyi listeye kaydeden metodu da çalıştıracaktır.

Artık tüm siparişlerin kaydedildiği bir sınıf değişkenimiz olduğuna göre bu değişkeni kullanacak ve aynı zamanda siparişleri ekrana yazdırmayı sağlayan nesne metodunu da kullanacak bir sınıf metodu yazabiliriz;

class Siparis:
  siparisler=[]

  def __init__(siparis, siparisNo, urunAdi, siparisAdedi, siparisTutari):
    siparis.siparisNo=siparisNo
    siparis.urunAdi=urunAdi
    siparis.siparisAdedi=siparisAdedi
    siparis.siparisTutari=siparisTutari
    siparis.siparisKaydet()

  def siparisGoruntule(siparis):
    print()
    print("Sipariş No: ", siparis.siparisNo)
    print("Sipariş Edilen Ürün: ", siparis.urunAdi)
    print("Satın Alınan Ürün Adedi: ", siparis.siparisAdedi)
    print("Sipariş Tutarı: ", siparis.siparisTutari)
    print("---------------------------------------------")
    print()

  def siparisKaydet(siparis):
    Siparis.siparisler.append(siparis)
    print("{} numaralı sipariş sipariş defterine kaydedilmiştir.".format(siparis.siparisNo))

  @classmethod
  def tumSiparisler(sinif):
    for x in sinif.siparisler:
      sinif.siparisGoruntule(x)


siparis1=Siparis(1,"Peppino Kurşun Kalem",12,42.50)
siparis2=Siparis(2,"Peppino Boya Kalemi",3,32.25)
siparis3=Siparis(3,"A4 Boy 120 Yapraklı Kareli Defter",2,20)

Siparis.tumSiparisler()

Çıktı:

1 numaralı sipariş sipariş defterine kaydedilmiştir.
2 numaralı sipariş sipariş defterine kaydedilmiştir.
3 numaralı sipariş sipariş defterine kaydedilmiştir.

Sipariş No: 1
Sipariş Edilen Ürün: Peppino Kurşun Kalem
Satın Alınan Ürün Adedi: 12
Sipariş Tutarı: 42.5
---------------------------------------------


Sipariş No: 2
Sipariş Edilen Ürün: Peppino Boya Kalemi
Satın Alınan Ürün Adedi: 3
Sipariş Tutarı: 32.25
---------------------------------------------


Sipariş No: 3
Sipariş Edilen Ürün: A4 Boy 120 Yapraklı Kareli Defter
Satın Alınan Ürün Adedi: 2
Sipariş Tutarı: 20
---------------------------------------------

Sınıf metodları nesne oluşturulmasına gerek kalmadan da kullanılabildiği için modül olarak eklendiğinde sınıf_adı.metod_adı şablonuyla direkt olarak erişilip kullanılabilirler.

 

Statik Metodlar

Önceki başlıklarda da öğrendiğiniz şekilde; nesneler ile ilgili __init__() metoduyla oluşturulmuş değişkenleri metodlarınız içinde kullanacaksanız nesne metodlarını, sınıf değişkenlerini metodlarınız içinde kullanacaksanız sınıf metodlarını kullanıyorsunuz. Ancak bazı metodlarda nesnelerin ya da sınıfların değişkenlerinden hiç birini kullanmanız gerekmez. Bu durumda da @staticmethod dekoratörünü kullanarak statik metodları oluşturuyoruz.

Bu şekilde sınıfın ya da nesnelerin değişkenlerini kullanmayacak da olsa, sınıf ile alakalı olan metodları sınıf dışına yazmak yerine sınıf içinde tutarak bütünlüğü koruyoruz. Bu durum modül olarak eklendiğinde sınıf adı ile kullanılabilir olmasını da sağlıyor.

Örneğin uygulamanız için bir menü yapmak isterseniz herhangi bir sınıf ya da nesne değişkeni ile bağlantı kurmanız gerekmeyecektir, ama sınıf ve nesne metodlarını kullanmak isteyeceksiniz. Öyleyse sınıf içinde statik metod yazarak bunu gerçekleştirebilirsiniz;

 

class Siparis:
  siparisler=[]

  def __init__(siparis, siparisNo, urunAdi, siparisAdedi, siparisTutari):
    siparis.siparisNo=siparisNo
    siparis.urunAdi=urunAdi
    siparis.siparisAdedi=siparisAdedi
    siparis.siparisTutari=siparisTutari
    siparis.siparisKaydet()

  def siparisGoruntule(siparis):
    print()
    print("Sipariş No: ", siparis.siparisNo)
    print("Sipariş Edilen Ürün: ", siparis.urunAdi)
    print("Satın Alınan Ürün Adedi: ", siparis.siparisAdedi)
    print("Sipariş Tutarı: ", siparis.siparisTutari)
    print("---------------------------------------------")
    print()

  def siparisKaydet(siparis):
    Siparis.siparisler.append(siparis)
    print("{} numaralı sipariş sipariş defterine kaydedilmiştir.".format(siparis.siparisNo))
    print()

  # Sınıf Metodu tanımlama
  @classmethod
  def tumSiparisler(sinif):
    for x in sinif.siparisler:
      sinif.siparisGoruntule(x)

  # Statik Metod tanımlama
  @staticmethod
  def menu():
    print("--MENÜ--")
    print("- 'S'ipariş Görüntüle")
    print("- 'T'üm Siparişleri Görüntüle")
    print("- 'Ç'ıkış")
    print("-------------------------------")
    print("Kullanmak istediğiniz menü özelliği için işaretli tuşa basınız.")
    kullanici_secimi=input()
    if kullanici_secimi == "s":
      siparis_no=input("Lütfen görüntülemek istediğiniz sipariş numarasını giriniz: ")
      Siparis.siparisGoruntule(Siparis.siparisler[int(siparis_no)-1])
      Siparis.menu()
    elif kullanici_secimi == "t":
      Siparis.tumSiparisler()
      Siparis.menu()
    elif kullanici_secimi == "ç":
      print("Uygulamadan çıkış yaptınız.")
    else:
      print("Menüde tanımlanmayan bir tuşa bastınız. Lütfen tekrar deneyiniz.")
      Siparis.menu()

siparis1=Siparis(1,"Peppino Kurşun Kalem",12,42.50)
siparis2=Siparis(2,"Peppino Boya Kalemi",3,32.25)
siparis3=Siparis(3,"A4 Boy 120 Yapraklı Kareli Defter",2,20)

Siparis.menu()

Çıktı:

1 numaralı sipariş sipariş defterine kaydedilmiştir.

2 numaralı sipariş sipariş defterine kaydedilmiştir.

3 numaralı sipariş sipariş defterine kaydedilmiştir.

--MENÜ--
- 'S'ipariş Görüntüle
- 'T'üm Siparişleri Görüntüle
- 'Ç'ıkış
-------------------------------
Kullanmak istediğiniz menü özelliği için işaretli tuşa basınız.

Kullanıcı ile etkileşimli hale gelen uygulamamızda klavyenizden s harfine bastığınızda size sorulan sipariş numarasını girerek ilgili sipariş kayıtlarını görebilirsiniz. Daha sonra koşullu ifade içine de yerleştirdiğimiz Siparis.menu() fonksiyon çağrısı ile menü tekrar başlatılacak ve siz kalvyenizden ç harfine basana kadar, isterseniz tek tek siparişleri görebilecek ya da t harfine basıp tüm siparişleri görebileceksiniz.

 

Nesne Verilerini Değiştirmek ya da Silmek

Bir sınıftan oluşturulmuş nesnelerin depoladıkları verileri nokta notasyonu ile yeni bir değer atayarak değiştirebilirsiniz. Tıpkı değişkenlere yeni değer atayarak değiştirebildiğiniz gibi;

personel3.deneyimSuresi=6
print(personel3.ad ,"için güncellenmiş deneyim süresi: " , personel3.deneyimSuresi, "yıl")

Çıktı:

Ceren için güncellenmiş deneyim süresi: 6 yıl

Bir veriyi silmek isterseniz de; del anahtar kelimesinden faydalanabilirsiniz;

del personel3.deneyimSuresi
print("Deneyim Süresi: " , personel3.deneyimSuresi)

Çıktı:

Traceback (most recent call last):
File "main.py", line 64, in <module>
print("Deneyim Süresi: " , personel3.deneyimSuresi)
AttributeError: 'Personel' object has no attribute 'deneyimSuresi'

Eğer silinmiş olan bir veriye erişmek isterseniz nesnenin o özelliğe sahip olmadığı ile ilgili bir hata alırsınız. Yani del anahtar kelimesi o nesnenin sadece değerini değil, belirttiğiniz özelliğini siliyor. Eğer hata almak istemiyorsanız özelliği silmek yerine atama yaparak veriyi boşaltmak daha mantıklıdır;

personel2.deneyimSuresi=""
print("Deneyim Süresi: " , personel2.deneyimSuresi)

Çıktı:

Deneyim Süresi: Belirtilmemiş

del anahtar kelimesini kullanırken dikkat etmeniz gereken bir diğer nokta da, eğer bir özellik belirtmek yerine nesneyi parametre olarak verirseniz tüm nesneyi siler.

del personel2
print(personel2.ad)

Çıktı:

Traceback (most recent call last):
File "main.py", line 72, in <module>
print(personel2.ad)
NameError: name 'personel2' is not defined

Silinmiş olan bir nesneye ulaşmak isterseniz, tanımlı olmadığı ile ilgili bir hata alacaksınızdır.