Python Programlama Dili

Bölüm 1

Başlangıç Bilgileri

Top Navigasyon

Ders 5

1.15 - Python Nesne Tipinin Tanıtımı

Matematik ile ilgili programlar daha çok fonksiyonel programlardır. Nesne Yönelimli Programlama (Object Oriented Pogramming = OOP) ise, daha çok sosyal bilimlerde uygulama alanı bulan bir programlama yöntemidir. Buna rağmen, herhangibir kısıtlama yoktur ve Nesne Yönelimli Programlama yöntemleri her türlü matematik çalışmada da rahatlıkla uygulanabilir.

Programlama açısından nesneler bir bilgi agregasyonudur. Nesnelerin bazı özellikleri olabilir. Nesne özellikleri, ya bir sabit değer, ya da bir fonksiyon olabilir. Sabit değerli özelliklere öznitelikler (attributes) adı da verilmektedir. Nesnelere bağlı fonksiyonlara "metot" adı verilir. Metotların formal parametreleri, nesnenin sabit değerli öznitelikleridir (attributes).

Nesneler, önce bir sınıf (class) modeli olarak tanımlanırlar. Bu sınıf modelinin tanımlanması aynı fonksiyon modellerinin tanımlanması gibidir. Yani bir takım sanal öğelerle, gerçek nesne örneğinin ne şekilde oluşacağı, özelliklerinin neler olacağı, metotlarının nasıl çalışacağı tanımlanır. Buna sınıf düzeyinde (class level) tanımlama denilir

Sınıf düzeyinde tanımlama tamamlandığında, artık nesnenin modeli belirlenmiş olur. Bu modele uygun, gerçek argümanlar kullanılarak, binlerce örnek yaratılabilir. Her örneğin yapısı aynen sınıf örneğinde tanımlandığı gibidir. Her örneğin özellikleri sayı ve veri tipi olarak aynen nesne sınıfında tanımlanmış olduğu gibidir. Metotlar, yine aynen nesne sınıfında formal değişkenlerle tanımlanmış olan işlevlerini gerçek argümanlarda da tekrar ederler.

Bir nesne türünün örnekleri, yaratıldıktan sonra, yaratıldıkları nesne sınıfından bağımsızdır. Yaratılan nesne örneklerine yeni özellikler eklenebilir, fakat, bir nesne örneğinde tanımlanmış olan yeni özellikler, ek özelliklerin tanımlanmış olduğu sınıf örneğinin yaratılmış olduğu nesne sınıfınının tanımına aksetmez. Nesne sınıfının yapısı ancak sınıf düzeyinde değiştirilebilir. Sınıf örneği düzeyinde tanımlanmış olan ek özellikler, sadece tanımlandıkları sınıf örneği kapsamında kalırlar ve ne ana nesne sınıfının tanımına, ne de daha sonra yaratılacak olan nesne örneklerine bu ek özellikler yansımaz. Bir nesne örneğinde yaratılan ek özellikler, sadece yaratıldıkları nesne örneğinde geçerlidir.

Nesnelerle kalıtım özelliği vardır. Yani bir nesne sınıfı yaratıldıktan sonra, tanımlanmış olan bu sınıfın özellik ve metotlarına ek özellik ve metotlar gerektiren yeni bir nesne sınıfına gereksinme olabilir. Kod ekonomisinin sağlanması açısından, yeni sınıfı eski sınıfın bir alt sınıfı olarak tanımlanır. Böylece, bu yeni sınıf, üst sınıfın bütün özelliklerini edinmiş olur ve sadece yeni özelliklerin oluşturulmasına gerek kalır. Buna miras (inheritance) adı verilir. Python programlama dilinin avantajlı bir yönü olan, birden çok sınıftan miras alma (çoklu kalıtım) (multiple inheritance) olanağı da sağlanmıştır.

Bazı nesne metotları, benzer yapıdaki (homomorf) nesnelere uygulanabilir. Buna Polimorfi denilir. Polimorfi, kod ekonomisi sağlar, fakat uygulanması hassastır ve çok dikkat ister. Fazla bir uygulama alanı da yoktur.

Bir sözel veriden oluşan ve adı İnsanYaşı olan bir sınıf yapısı düşünelim (nesne sınıfları ilk karakteri büyük harf olan tanıtıcılarla tanıtılırlar). Bu nesnenin adı yaş olan bir tamsayısı verisi olan özelliği olsun (nesne özellikleri, ilk karakteri küçük harf olan tanıtıcılarla tanıtılırlar). Bu nesne sınıfının adı hasan olan bir örneğini yaratalım nesne sınıfı örnekleri ilk karakteri küçük harf olan tanıtıcılarla tanıtılırlar). İnsanYaşı nesne sınıfının bir örneği olan hasan verisi oluşturulurken, zorunlu olarak yaş özelliğine bir değer atanır. İnsanYaşı nesne sınıfının bir örneği olarak, hasan adlı nesne oluşturulduktan sonra yaş özelliğinin değerine erişmek için, hasan.yaş şeklinde nokta notasyonu kullanılır. Hemen hemen, tüm program dillerinde, nesne özelliklerine nokta notasyonu ile erişilir.

Bazı durumlarda içiçe nesneler kullanılır. Yani bir nesnenin özelliği, bir başka nesne olabilir. İkinci nesnenin özelliklerinden birisi veya hepsi başka nesneler olabilir. Bu bir zincirleme tanım olayını tanımlar. Örnek olarak Istanbul nesnesinin bir özelliği Beşiktaş nesnesi olsun, bunun da bir özelliği Levent nesnesi olsun, bunun da bir özelliği FecriEbcioğlu özelliği olsun (Feri Ebcioğlu çok iyi bir müzik ve şarkı sözü yazarı idi. Çok zarif bir insan olan yazarın adı, rahmetli olmasından sonra, Levent semtinde oturduğu sokağa verilmiştir). Bu bir tamsayı verisi olsun ve sokaktaki bina sayısını belirtsin. Bu veriye erişim,

Istanbul.Beşiktaş.Levent.FecriEbcioğlu

şeklinde gerçekleşir. Böyle içiçe nesne özellikleri erişimi, "tam kalifiye isim" ("fully qualified name") olarak adlandırılır. İçiçe nesnelerin özelliklerine tam kalifiye isimleri ile erişim, özellikle Python modüllerinde tanımlı bazı nesnelerin özelliklerine erişimde kullanılır. İçiçe nesne tanımlarının küçümsenmemesi gerekir. Örnek olarak, yukarıdaki örnekte, Istanbul şehrinin, tüm ilçelerinin, tüm semtlerindeki sokaklarda bulunan, ev sayılarının envanteri oluşturulabilir. Bu büyük bir olanaktır. Veri temelleri böyle oluşturulur.

1.15.1 - Sınıf Örnekleri ve İsim Alanları

Nesne yönelimli programlama, her programlama dili için farklı bir şekilde oluşturulur. Python için de bu yöntemleri tanımaya çalışalım. ilk olarak, sadece özelliğ olmayan bir nesne sınıfı tanımlayalım ve bu nesne sınıfından bir örnek oluşturup, bu örneğe yeni özellikler ekleyelim.

>>>class Toplama :
...pass enter
... enter

>>>topla =Toplama()enter

>>>topla.değer1= 25enter
>>>topla.değer1 enter
25

Burada, ilginç bir olay ile karşı karşıyayız. Toplama adlı bir sınıf tanımlanmış, fakat bu sınıfın herhangibir özelliği tanımlanmamış. Yani, bu bir boş sınıf. Bu sınıf, tanımından sonra da pass geçilmiş. Bunun anlamı Python derleyicisine, şimdilik bu sınıf ile ilgili herhangibir işlemin yapılmayacağının belirtilmesidir. Sonra, bu sınıfa ait topla adlı bir örneğin yaratıldığı görülüyor. Ana sınıfa ait hiçbir özellik tanıtılmamış olduğundan, yaratılmış olan topla adlı sınıf örneğinde de başlangıçta hiçbir özellik yoktur.

Yeni oluşan toplam adlı boş bir sınıf örneğine, nokta notasyonu kullanarak yeni özellikler atayabiliriz. Örnekte bunun topla.değer1=25 şeklinde yapıldığını görüyoruz. Bu atamadan sonra, değer1 tanıtıcısı ile yeri işaretlenmiş bir bellek alanına 25 tamsayı değeri yerleştirilmiş oluyor. Buraya kadar çok iyi...

Burada değer1 tanıtıcısına dikkat edelim. Bu tanıtıcının işaret ettiği bellek alanı değerine ancak değer1 tanıtıcısının çağrılması ile erişilebilir. Fakat, değer1 tanıtıcısına her yerden erişim olanağı yok. Bu tanıtıcı, topla sınıf örneğinin bir özelliği olarak tanıtılmış ve ancak topla sınıf örneğinin bir özelliği olduğu, topla sınıf öneğine erişebilecek bir yerden belirtildikçe erişilebilir. Bu şekilde topla sınıf örneğinin bir alan olduğu görülüyor. Bu alanda özellikler yaratılabiliyor ve bu özellklere anacak topla sınıf örneğinin adı belirtilerek erişilebiliyor. Bu durumda topla ismi bir alan ismi olarak ortaya çıkıyor. Her bir sınıf örneği bir isim alanı oluşturuyor ve bu isim alanı altında bir özellik tanımlandığında, bu bir değişken tanımlamakla eşdeğer bir işlem oluyor. Yani değişkenler, aslında bir ism alanı altında tamımlanmış özelliklerdir. İsim alanları konusuna ileride döneceğiz fakat şimdiden konuyu özümsemekte yarar var.

Buradan kalifiye isimler hakkında da bir fikir alma olanğı bulunuyor. Kalifiye isimler, bir isim alanında tanımlanmış özellikleri belirtirler. Bir isim alanında tanımlanmış bir özelliğe, o isim alanı dışından erişim olanağı yok. Ayrıca, o isim alanına da ancak erişim hakkımız olduğunda erişebiliyoruz. Özetle, toplam.değer1, toplam isim alanında tanımlanmış bir özelliği, veya başka bir deyişle toplam isim alanında tanımlanmış bir değişkeni belirten bir tanıtıcıdır. Herkes bu olayı nasıl algılamak isterse o şekilde algılayabilir.

1.15.2 - Bir Nesne Sınıfının Yapılandırılması

Boş bir nesne sınıfı yaratmanın hiçbir avantajı yoktur. Yukarıdaki örnekte görüldüğü gibi, boş bir sınıfın örnekleri de boş bir yapı ile yaratılacaklardır. Bunlara en kolay olarak değer özellikleri tanımlanabilir. Bir sınıf örneğine özgü metotların tanımı zor ve kesinlikle gereksizdir. Ayrıca bu özellikler de, bu sınıfın başka örneklerinde geçerli olmazlar. Oysa gereksinme bunu tam aksi yönündedir. Bir sınıfın özellikleri, sınıf bazında tanımlanmalı ve gerekirse ön değerleri verilmelidir. Sınıf örnekleri de sınıf bazında belirlenmiş özelliklerle oluşmalı ve aynı sınıfa ait farklı özelliler sadece değer özelliklerinin değerleri ile birbirlerinden fark edilmelidirler.

Yukarıdaki örnekte, hem sınıf tanımı, hem de sınıf örneği tanımının nasıl yapılabileceğini gördük. Şimdi, yine çok kolay olan, sınıf yapısı düzeyinde özellikler belirlemeye çalışalım. Sınıf düzeyinde tanımlanan özellikler, her örneğe kalıtımla geçerler.

İlk olarak öntanımlı __init__ metodunu tanıyalım. Bu metot, sınıf tanımından, sınıf örneklerinin yapısını belirlemek için kullanılan, hem yapılandırma (constructor), hem de ilk değer verme (initialise) işlevini yapan bir fonksiyon olarak düşünülebilir. Bu fonksiyonu, yukarıdaki örnekte boş bir sınıf olarak oluşturduğumuz, Toplama sınıfını yapılandırmak için aşağıdaki örnekte kullanalım:

>>>class Toplama :  enter
...def __init__(self) : enter
...self.değer1 = 25 enter
...self.değer2 = 50 enter
... enter
>>>toplam = Toplama() enter
>>>toplam.değer1 enter
25

Burada, sınıf tanımı ile birliklte, __init__() metodunu da tanımlıyoruz. Bu metot, yapılandırılan nesnenin özelliklerini oluşturur ve bunlara ilk değerlerini verir. Programda, __init__ () metodunun formal parametresi olarak öntanımlı self değeri belirtiliyor. Kullanılan self saklı sözcüğü, yapılandırılan nesneyi belirtir. Yani, self yerine Toplama olarak okuyabilirsiniz. Böylece __init__() metodunun, self argümanı ile, self saklı sözcüğünün belirttiği, Toplama sınıf nesnesini işleyeceği belirtilmiş oluyor. Bundan sonra, __init__() metodunun içinde, Toplama sınıfının özellikleri tanımlanıyor ve ilk değerleri veriliyor.

Program __init__() metodunu terkettiğinde, artık Toplama sınıfı yapılandırılmıştır. Yani özellikleri belirlenmiş ve bu özelliklerine ilk değerler atanmıştır. yine de, bu sınıfa ait henüz bir isim alanı açılmamıştır. İsim alanları sınıf örnekleri yaratıldığında açılırlar ve her sınıf örneği için ayrı bir isim alanı açılır. Çünkü, her yeni sınıf örneğinin sınıf tanımından gelen ve diğer sınıf örnekleri ile aynı olan özelliklere sahip olması ve bu özelliklerinin her sınıf örneğine özgü farklı değerleri olabilecektir. Zaten değerler de aynı olsa, ayrı bir sınıf örneğinden bahsetmek olanağı olmazdı. Ayrıca her sınıf örneğinin kendine özgü tanımlanmış özellikleri de olabilir. Bunun için, her sınıf örneği farklı bir isim alanı oluşturur. Yukarıdaki örnekte, Toplama sınıfının örneği olarak toplam nesnesi yaratılmıştır. Tanıtılmış olan toplam nesnesi ile birlikte toplam isim alanı da açılmıştır.

Toplam isim alanında tanımlı iki özellik (veya değişken, aslında her ikisi de aynı şeydir) bulunmaktadır. Bu değişken değerlerine toplam isim alanından erişilebilir. Aynı şekilde, toplam isim alanına erişebilen bir isim alanından da bu değişken değerlerine erişilebilir. Bulunduğumuz isim alanında tanımlandığı için, toplam isim alanına erişimiz bulunmaktadır. Bulunduğumuz isim alanından değer1 değikenine, önce toplam isim alanına erişip bu isim alanımdan değişken1'i çağırarak erişebiliriz. Kalifiye isim olarak da adlandırılan bu erişim yöntemi, toplam.değer1 şeklinde, nokta notasyonu kullanılarak uygulanabilir. Yukarıdaki örnekte, toplam sınıf örneğinin özellik değerlerine (veya toplam isim alanının değer1 değişkeninin değerlerine) nokta notasyonu ile erişim yapıldığı ve döndürülen geçerli (güncel) değerin konsolda görüntülendiği görülüyor.

Bir sınıf yapılandırılmasında, __init__() metodu ile yapılandırılan özellikler, sınıf örnekleri özellikleridir. Yani bu sınıfın yaratılacak tüm örneklerinde, __init__() metodu ile yapılandırılmış olan özellikler, öntanımlı değerleri ile birlikte bulunacaktır.

Toplama sınıfının örneklerinde, bu tür bir yapılandırma ile değer1 ve değer2 olarak iki özellik bulunuyor ve bunların değerleri daima 25 ve 50 oluyor. Bu yapılandırma yöntemi ile bundan kaçış yok. Yani, bu sınıftan her yaratılan sınıf örneğinin özellik değerleri, önceden tanımlanmış sabit değerler ile yaratılıyor. Oysa, gereksinme tam bunun aksi yönündedir. Her sınıf örneği, tüm sınıfa ait ortak özellik değerleri ile değil, kendi özgül değerleri ile yaratılmak ister. Yukarıdaki programda, bunu sağlayacak değişikliler yapabilirsek, daha evrensel bir sınıf tasarımı yapmış oluruz ve bu sınıfın yaratılacak örnekleri daha özgün olurlar. Bu çalışmayı başlatalım.

Programda yapılacak ilk değişiklik, _init__() metodu ile yaratılan sınıf örneği özelliklerine sabit ön değerler verilmesinden vazgeçmek olmalıdır.

>>>class Toplama :  enter
...def __init__(self , a , b) : enter
...self.değer1 = a enter
...self.değer2 = b enter
    
...def toplamaYap(self) : enter
...return self.değer1  + self.değer2
... enter >>>toplam = Toplama(5,5) enter >>>toplam.toplamaYap() enter 10

Yukarıdaki programda ilgi çeken ilk nokta, sınıf tanımı yapılırken, örnek özellikleri olan değer1 ve değer2 değerleri için, formal parametreler olan a ve b değerlerinin kullanılmış olmasıdır. Toplama sınıfının bir örneği olan topla nesnesi oluşturulurken, a ve formal parametrelerinin yerine 5,5 olarak gerçek argümanlar verilmiştir. Bu şekilde, topla sınıf örneğinin deger1 ve değer2 özelliklerinin (veya topla isim alanının değer1 ve değer2 değişkenlerinin) değeri olarak 5 yerleştirilmiştir.

Toplama sınıfının bir örneği olan topla nesnesi oluşturulduktan sonra, sınıf tanımında tanımı yapılmış olan toplamaYap() metodu çağrılarak, topla sınıf örneğinin, değer1 ve değer2 özellikleri toplanmış ve elde edilen sonuç geri döndürülerek konsolda görüntülenmiştir

Yukaarıdaki örnek çok uygulanan bir nesne sınıfı yaratma ve yaratılmış olan bu nesne sınıfına ait nesne örnekleri yaratma yöntemidir. Bu yöntemde her sınıf örneği, başlangıçta verilen özellik değerleri ile yaratılmakta ve yaratılan nesne örneklerine, sınıf tanımı sırasında tanımlanmış olan metotlar uygulanmaktadır. Bu konuda ileride başka uygulama örnekleri de yapacağız.