12. Nesne Yönelimli Programlama – Python

Python her ne kadar fonksiyonel bir dil olsa da var olduğundan beri nesne yönelimli bir dil olmuştur. Sınıf oluşturma ve nesne yaratma gibi temel işlemler son derece kolaydır. Bu bölüm Python’ın nesne yönelimli taraflarını anlatmaya ayrılmıştır.Nesne Yönelimli Programlama (Object-Oriented Programming – OOP) Bilgisayar Mühendisliği Bölümlerinin en temel derslerinden biridir. Bu dersin tüm konularını sadece bu bölümü sıkıştırmak çok zordur. Bu bölümde en temel konular basit örneklerle açıklanacaktır. Bilginiz yok ise yazı içinde anahtar kelimeleri kullanarak konu hakkında daha fazla bilgi bulabilirsiniz. Öncelikle bir kaç terminolojik tanım vererek bazı temel konuları açıklayalım.

  • Sınıf (Class): Sınıfın herhangi bir nesnesini karakterize eden bir özellik kümesi tanımlayan bir nesne için kullanıcı tanımlı bir prototiptir. Sınıf özellikleri üyelere, değişkenlere ve metotlara sahiptir. İyi bir sınıf tasarımı için yazılımcının soyutlama (abstraction) işlemini çok iyi yapması gerekir. Sınıf aslında yazılımcının kendi dünyasıdır.
  • Sınıf değişkeni (Class variable): Bir sınıfın tüm örnekleri tarafından paylaşılan bir değişkendir. Sınıf değişkenleri bir sınıf içerisinde ancak sınıfın herhangi bir metodunun dışında tanımlanır.
  • Veri üyesi (Data member): Bir sınıf ve nesnelerle ilişkili verileri tutan bir sınıf değişkeni veya örnek değişkenidir.
  • Fonksiyon aşırı yüklenmesi (Function overloading) – Belirli bir fonksiyona birden fazla davranışın atanmasıdır. Yapılan işlem, ilgili nesne veya argüman türlerine göre değişir.
  • Örnek değişkeni (Instance variable): Bir yöntem içinde tanımlanan ve yalnızca bir sınıfın geçerli örneğine ait olan bir değişkendir.
  • Kalıtım (Inheritance): Bir sınıfın özelliklerinin, ondan türetilen diğer sınıflara aktarılmasıdır.
  • Örnek (Instance): Belirli bir sınıfın bireysel bir nesnesidir. Örneğin, bir Circle sınıfına ait bir nesnedir. Başka bir deyişle Circle sınıfının bir örneğidir.
  • Örnekleme (Instantiation): Bir sınıfın örneğinin oluşturulmasıdır.
  • Metot (Method): Sınıf tanımlanırken tanımlanan özel bir fonksiyon türüdür.
  • Nesne (Object): Sınıfı tarafından tanımlanan bir veri yapısının benzersiz bir örneğidir. Bir nesne, hem veri üyelerini (sınıf değişkenleri ve örnek değişkenleri) ve yöntemleri içerir.
  • Operatörlerin aşırı yüklenmesi (Operator overloading): Belirli bir operatöre birden fazla işlevin atanmasıdır.

12.1. Sınıf Oluşturma

class ifadesi yeni bir sınıf tanımı oluşturur. Sözdizimi:

  • Python kodu içinden ClassAdi.__doc__ ile ulaşabildiğimiz sınıf hakkında bir açıklama metnine sahiptir. Bu kısım seçimliktir.
  • class_kismi sınıf üyelerini, veri özelliklerini ve fonksiyonları içerir.

Her programlama dilinin kendine özgü özellikleri vardır. Bu bölümde .Net ve Java ile kıyaslamalar yapılacaktır.

  • Ogrenci_sayisi değişkeni bu sınıfın tüm örnekleri (nesneleri) arasında paylaşılan değer olarak bir sınıf değişkenidir. Sınıf ismi.değişken ismi şeklinde (bu örnek için Ogrenci.Ogrenci_sayisi şeklinde) sınıf dışından ve sınıf içinden ulaşabiliriz. .Net ve Java’daki statik değişken kavramına benzemektedir. Ancak, bu programlama dillerinde static ifadesi belirtilmelidir. Python programlama dilinde ise böyle bir özelliğine ihtiyaç yoktur.
  • __init__() – (başlangıç ve son iki alt çizgili) yapıcı (constructor) olarak bilinen sınıf ilk oluşturulan yapılacak işlemlerin tanımlandığı özel bir metottur. Python, bu sınıfın nesne/örnek oluştururken oluştururken çağrılan ilk metottur.
  • Normal bir fonksiyon tanımlar gibi sınıf metotlarını tanımlanabilir.
  • Sınıftaki tüm metotlar için self ilk argüman olarak kullanılır. self nesne üzerinden ulaşacağımız anlamına gelir. Python sizin için self argümanları listeye ekler; metotları çağırdığınızda bunu eklemeniz gerekmez.

12.2. Sınıftan bir nesne – örnek oluşturma ve erişim

Bir sınıfın örneklerini oluşturmak için, sınıf adını kullanarak sınıfı çağırırsınız ve __init__ yönteminin kabul ettiği argümanları iletirsiniz.

.Net ve Java gibi dillerde yeni bir örnek oluşturmak için new anahtar kelimesi kullanılır. Ancak, Python’da direkt atama işlemi ve sınıf ismi çağrılır.

Nesnenin özelliklerine ulaşmak için nokta operatörü ile nesne içindeki özelliklere erişebiliriz. Örneğin,

12.3. Örnek oluşturduktan nitelik kontrolü

Herhangi bir zamanda sınıfların ve nesnelerin niteliklerini ekleyebilir, kaldırabilir veya değiştirebilir.

Özelliklere erişmek için normal ifadeleri kullanmak yerine, aşağıdaki fonksiyonları kullanabilirsiniz:

  • getattr (obj, name [, default]): nesnenin özelliğine erişmek için kullanılır.
  • hasattr (obj, name): bir özellik var olup olmadığını kontrol etmek için kullanılır. (True / False)
  • setattr (obj, name, value) – bir özellik belirlemek için kullanılır. Özellik yoksa, o zaman yaratılır.
  • delattr (obj, name) – bir özelliği silmek için kullanılır.

12.4. Yerleşik sınıf özellikleri

Her Python sınıfı yerleşik özellikleri takip eder ve herhangi bir özellik gibi nokta operatörünü kullanarak erişilebilir.

  • __dict__ : Sınıfın ad alanını içeren sözlük.
  • __doc__ : Tanımlanmamışsa, sınıf belgelendirme metni içerir.
  • __name__ : Sınıf adı.
  • __module__ : Sınıfın tanımlandığı modül adı. Bu özellik, etkileşimli modda “__main__” şeklindedir.
  • __bases__ : Temel sınıf listesindeki oluşum sırasına göre, temel sınıflarda muhtemelen boş bir tüpledir.

12.5. Nesneleri yok etme – Garbage collection

Bir nesne yönelimli dilin en önemli özelliği belleği dinamik olarak kullanmasıdır. Python, bellek alanınındaki gereksiz nesneleri (yerleşik tipler veya sınıf örnekleri) otomatik olarak siler. .Net ve Java’da olduğu gibi Python’un periyodik olarak kullanımda olmayan bellek bloklarını sildiği süreç Garbage collection (Çöp Toplama) olarak adlandırılır. Python’un çöp toplayıcısı, program yürütme sırasında çalışır ve bir nesnenin referans sayısı sıfıra ulaştığında tetiklenir. Bir nesnenin referans sayısı, kendisine işaret eden diğer adların sayısı değiştiğinde değişir. Bir nesnenin referans sayısı, yeni bir ad verildiğinde veya bir konteynere (liste, tuple veya sözlük) yerleştirildiğinde artar. Nesnenin referans sayısı del ile silindiğinde azalır, referansı yeniden atar veya referans kapsam dışı kalır. Bir nesnenin referans sayısı sıfıra ulaştığında, Python otomatik olarak toplar.

Normalde bir çöp toplayıcının bellekte kullanılmayan blokları geri aldığını fark etmezsiniz. Sınıflara destructor (yıkıcı) denilen bir metotla yıkılma işlemi sırasında çalışan özel bir metot yazılabilir. Örneğin,

Üç nesne adres olarak birbirine bağlanmış ve üç nesnede aynı adresi gösteriyor. Ardından tüm referanslar silinince destructor devreye girer.

12.6. Kalıtım (Inheritance)

Nesne yönelimli programlama gerçek dünyanın programlamaya arttırılma çabası olarak görülebilir. Gerçek dünyada sınıflar ve sınıflardan oluşmuş nesneler vardır. “Ol” denir, nesneler bilgisayar belleğinde oluşur. Gerçek dünya sınıflar ve sınıflar arasında ilişkiler mevcuttur. Kalıtım, sınıf ve sınıfı kullanan alt sınıflar olarak görülebilir. Alt sınıflar, üst sınıfın özelliklerini devralır ve bu özellikleri alt sınıfta tanımlanmış gibi kullanır. Hatta, bir alt sınıfta istenilen özellikler geçersiz kılınabilir. Sözdizimi:

Türetilmiş sınıflar, ana sınıflarına benzer şekilde beyan edilirler; ancak, sınıf adından sonra miras almak için temel sınıfların bir listesi verilir. Alt sınıflar fonksiyon parametresi gibi parantez içinde yazılır. Java’da extends ve .Net ise “:”‘den sonra alt sınıflar verilirken Python daha farklı bir kullanım söz konusudur. Basit bir örnekle açıklayalım:

Benzer bir yolla, birden fazla sınıfı bir sınıfta kalıtım için kullanabilirsiniz. .Net ve Java’da bir sınıf için bir base sınıf kullanılabiliyordu, ancak Python bu konuda esnekliğini gösterir. Örneğin,

İki sınıf ve nesnelerin ilişkilerini kontrol etmek için issclass () veya isinstance () fonksiyonlarını kullanabilirsiniz.

  • issubclass (alt_sinif, ana_sinif) eğer sınıflar arası bir ilişki var ise fonksiyon True değerini döndürür.
  • Nesnenin bir sınıfla ilişkisi olup olmadığını bulmak için isinstance (obj:nesne, Class:Sınıf) fonksiyonu true değerini döndürür.

12.7. Geçersiz kılma (Overriding)

Ana sınıftaki metotlarımızı her zaman geçersiz kılabilirsiniz. Ana sınıftaki metodu geçersiz kılmak için alt sınıfta aynı isimle bir fonksiyon yaratmamız yeterlidir. Örneğin,

12.8. Temel aşırı yükleme (overloading) yöntemleri

Aşağıdaki tabloda kendi sınıflarınızda geçersiz kılınabilecek bazı genel metotları listelenmektedir.

Metot Tanım ve Basit çağırma
__init__ ( self [,args…] ) Yapıcı – Constructor (seçimlik argüman sayısı): Bir nesne oluşurken ilk istekleri
Basit çağırma : obj = className(args)
__del__( self ) Yıkıcı – Destructor: Bir nesnenin ölüm anında son istekleri
Basit çağırma : del obj
__repr__( self ) Değerlendirilen katar gösterimi
Basit çağırma : repr(obj)
__str__( self ) Yazdırılabilir katar gösterimi
Basit çağırma : str(obj)

12.9. Operatörleri aşırı yükleme (Operator Overloading)

“+” karakteri iki string olunca birleştirme yaparken sayısal değerler olunca ise toplama işlemi yapar. Bu durumda + operatörünün duruma göre farklı davrandığı sonucu ortaya çıkar. Bu konuya operatörlerin aşırı yüklenmesi denir. Konuyu bir örnekle açıklayalım. x ve y özelliklerine sahip Vektor adında bir sınıfımız olsun. Bu vektörden iki nesne oluşturup + işareti koyarsak ne olur. Deneyelim.

“+” sınıfta nasıl kullanılacağına dair bir bilgi olmadığı için toplama işlemini yapamadı. Python bunun için __add__ metodu sunar. __add__ metodu içine + işleminin nasıl davranacağını belirleyebiliriz. Yukarıdaki sınıf içine sadece aşağıdaki satırları ekleyelim.

self’i birinci nesne ve other’ı da ikinci nesnedir. Bu iki nesne arasına “+” işareti gelince yeni bir Vektor objesi döndürülmektedir. print metodu içinde ise Vektor sınıfının __str___ metodu devreye girmektedir.

12.9. Veri gizleme

En temel erişim belirteçleri .Net ve Java için public, private ve protected ifadeleridir. Ancak, Python’da klasik bir değişken public konumunda iken değişkenin sol tarafına konan çift alt çizgi ile private özelliğini barındırır. Ayrıca, Python diğer programlama dillerinde olduğu gibi özel ifadelere ihtiyaç duymaz. Çift alt çizgili değişken sadece sınıf içinden görülebilir ve dışarıdan görülebilir değildir. Basit bir örnek ile açıklayalım.

Burada “__priSayac” değişkeni sınıf dışından ulaşılmayan bir değişkendir. Ancak, “say” metodu ile sınıf içinden bu değişkene ulaşabiliriz.