Nesne Yönelimli Programlama
Şimdiye kadar yaptığınız programlama prosedüreldi. Ancak, günümüzde birçok program Nesne Yönelimlidir. C++ ve Java gibi bilgisayar bilimlerinde genellikle OOP yöntemlerini kullanır. Her iki türü ve farklarını bilmek önemli olacaktır.
Yeni başlayanlar ve programcı olmayanlar genellikle OOP kavramını kafa karıştırıcı ve karmaşık bulurlar. Bu normal bir şey. Zorlanırsanız veya anlamazsanız lütfen bu konuyu ertelemeyin. Bu bölüm size yardımcı olmazsa, aklınızdaki sorunların üstesinden gelmek için kullanabileceğiniz birçok başka kaynak bulabilirsiniz.
Bu bölüm farklı derslere bölünecek. Her ders OOP’yi farklı bir şekilde açıklayacak. Neden? Çünkü OOP’un mümkün olduğunca kapsamlı bir şekilde kapsanmasını sağlamak için, OOP ÇOK ÖNEMLİDİR. Derslerden önce, her dersi anlamak için gereken temel kavramları, terimleri ve OOP’nin diğer önemli alanlarını açıklayan bir girişle başlayalım.
Giriş
Bir prosedürü bir işlev olarak düşünün. Bir işlevin belirli bir amacı vardır. Bu amaç, bir dosyadan bilgi almak, matematiksel hesaplamalar yapmak, verileri görüntülemek veya verileri işlemek olabilir. Genellikle, prosedürler düzenleme için koddan ayrı verileri kullanır. Bu veriler genellikle fonksiyonlar arasında geçirilir. Ancak bir program çok daha büyük ve karmaşık hale geldiğinde, bu durum sorunlara neden olabilir. Örneğin, bir ürün hakkındaki bilgileri değişkenlerde depolayan bir program tasarladınız. Bir müşteri bir ürün hakkında bilgi istediğinde, bu değişkenler farklı amaçlar için farklı işlevlere geçirilirler. Daha sonra, bu ürünlerde daha fazla veri depolandıkça, bilgileri bir listede veya sözlükte depolamaya karar verirsiniz. Programınızın çalışması için, şimdi bir listeyi veya sözlüğü kabul etmek ve işlemek için değişkenleri kabul eden her işlevi düzenlemeniz gerekir. Yüzlerce megabayt ve yüzlerce dosya boyutunda bir program için gereken zamanı hayal edin! Kodunuzdaki hataların oluşması, sadece büyük iş hacmi ve yazım hatası veya başka bir hata yapma olasılıkları nedeniyle neredeyse garanti edilebilir. Bu pek istediğimiz bir şey değil. Prosedürel programlama prosedürlere veya işlevlere göre düzenlenir. Ancak, OOP Nesneleri oluşturma merkezlidir. Bir nesneyi, prosedürlerde kullandığımız dosya ve verilerin bir tür “kombinasyonu” olarak düşünün. Teknik anlamda, Nesne, veri ve fonksiyonları (kod, işlevler vb.) içeren bir varlıktır.
Nesne içindeki verilere veri özniteliği denir.
Nesnenin içindeki işlevlere veya yordamlara metot/yöntem denir.
Veri özniteliklerini değişkenler olarak düşünün.
Yöntemleri işlevler veya prosedürler olarak düşünün.
Basit bir örneğe bakalım. Yatak odanızdaki ışık ve ışık düğmesi. Bunun için veri öznitelikleri aşağıdaki gibi olacaktır.
- isik_acik (True veya False)
- anahtar_pozisyonu (Yukarı veya Asağı)
- elektrik_akimi (True veya False)
Yöntemler aşağıdaki gibi olacaktır.
- anahtari_degistir
- elektrik_akimini_degistir
Veri öznitelikleri görülebilir veya görünmeyebilir. Örneğin, ışığa akan elektriği doğrudan göremezsiniz. Sadece elektrik olduğunu bilirsiniz, çünkü ışık yanar. Ancak, anahtarın konumunu (anahtar_pozisyonu) ve ışığın açık veya kapalı olup olmadığını görebilirsiniz (isik_acik). Bazı yöntemler özeldir. Bu, bunlara doğrudan değiştiremeyeceğiniz anlamına gelir. Örneğin, ışık için, kabloları kesmediğiniz sürece elektriğin akışını doğrudan değiştiremezsiniz. Ayrıca ışık açık veya kapalıysa doğrudan değiştiremezsiniz. Ancak, nesnedeki yöntemleri kullanarak bu öznitelikleri dolaylı olarak değiştirebilirsiniz. Faturanızı ödemezseniz, fonksiyon bu özniteliğin değerini YANLIŞ olarak değiştirir. Anahtarı çevirirseniz, anahtari_degistir
yöntemi isik_acik
özniteliğin değerini değiştirir.
Şimdiye kadar muhtemelen “Bunun Python ile ne ilgisi var?” veya “Anlıyorum, ancak bir Nesneyi nasıl kodlayabilirim?” diye düşünüyorsunuzdur. Neredeyse o noktaya geldik! Koda dalmadan önce bir kavramı daha açıklamalıyız.
Python’da, bir nesnenin veri öznitelikleri ve yöntemleri bir sınıf tarafından belirtilir. Bir sınıfı bir nesnenin planı olarak düşünün. Örneğin, eviniz – yaşadığınız nesne -, bungalovunuz, beşiğiniz veya her neyse, bir dizi şemaya dayanarak inşa edildi; Bu planlar evinizi, beşiğinizi tasarlamak için kullanılan sınıf olarak kabul edilir.
Yine, bir sınıf bize bir nesnenin nasıl yaratılacağını söyler. Teknik açıdan – bu burada önemlidir – bir sınıf bir nesnenin içindeki veri özniteliklerini ve yöntemlerini tanımlar.
Sınıf oluşturmak için bir sınıf tanımını kodlarız. Sınıf tanımı, bir nesnenin veri özniteliklerini ve yöntemlerini tanımlayan bir dizi deyimdir.
Birinci Ders
Aşağıda, bir kullanıcı tarafından girilen tek bir sayı üzerinde basit matematik gerçekleştiren bir program bulunuyor.
# Program by Mitchell Aikens # No Copyright # 2012 # Procedure 1 def main(): try: # Get a number to maniuplate num = float(input("Please enter a number to manipulate.\n")) # Store the result of the value, after it has been manipulated # by Procedure 2 addednum = addfive(num) # Store the result of the value, after it has been manipulated # by Procedure 3 multipliednum = multiply(addednum) # Send the value to Procedure 4 display(multipliednum) # Deal with exceptions from non-numeric user entry except ValueError: print("You must enter a valid number.\n") # Reset the value of num, to clear non-numeric data. num = 0 # Call main, again. main() # Procedure 2 def addfive(num): return num + 5 # Procedure 3 def multiply(addednum): return addednum * 2.452 # Procedure 4 def display(multi): # Display the final value print("The final value is ",multi) # Call Procedure 1 main()
“5” değerini girersek, çıktı aşağıda gösterildiği gibi olacaktır.
Please enter a number to manipulate. 5 The final value is 24.52
“g” değerini girip girişi düzeltip “8” değerini girersek, çıktı aşağıda gösterildiği gibi olur.
Please enter a number to manipulate. g You must enter a valid number. Please enter a number to manipulate. 8 The final value is 31.875999999999998
Aşağıda ise bir sınıf ve bu sınıfı kullanan bir program var. Bu Nesne Yönelimli Program, yukarıdaki prosedür programıyla aynı şeyi yapar. Sınıfa ve programa dalmadan önce bazı önemli OOP kodlama kavramlarını ele alalım. Bir sınıf oluşturmak için class
anahtar sözcüğünü kullanırız. Anahtar sözcükten sonra, sınıfınıza adlandırmak istediğiniz adı yazarsınız. Sınıfınızın adının CapWords kuralı kullandığı yaygın bir uygulamadır. Dirtysocks adında bir sınıf oluşturmak isteseydim, kod şöyle olurdu:
class DirtySocks
Sınıf ilk olarak gösterilir. Sınıfı kullanan program ikinci sıradadır.
# Filename: oopexample.py # Mitchell Aikens # No Copyright # 2012 # OOP Demonstration - Class class NumChange: def __init__(self): self.__number = 0 def addfive(self,num): self.__number = num return self.__number + 5 def multiply(self,added): self.__added = added return self.__added * 2.452
Yukarıdaki sınıfı kullanan program aşağıdadır.
# Filename: oopexampleprog.py # Mitchell Aikens # No Copyright # 2012 # OOP Demonstration - Program import oopexample maths = oopexample.NumChange() def main(): num = float(input("Please enter a number.\n")) added = maths.addfive(num) multip = maths.multiply(added) print("The manipulated value is ",multip) main()
Bu programa baktıktan sonra muhtemelen biraz kayboldunuz. Tamam. Sınıfı parçalayarak başlayalım. Sınıf “NumChange” olarak adlandırıldı. Bu sınıfın üç yöntemi var:
- __init__
- addfive
- multiply
Bu üç yöntemin her biri benzer bir koda sahip.
def __init__(self): def addfive(self,num): def multiply(self,added):
Her yöntemin nasıl “self” adlı bir parametreye sahip olduğuna dikkat edin. Bu parametre sınıfın her yönteminde bulunmalıdır. Bu parametrenin “self” olarak adlandırılması gerekmez. Ancak bu bir standart haline geldi. Dolayısıyla buna bağlı kalmanız gerektiğini unutmayın. Bu parametre her yöntemde gereklidir. Çünkü bir fonksiyon yürütülürken, hangi nesnenin özniteliklerini değiştireceğini/kullanacağını bilmesi gerekir. Her ne kadar bir nesnemiz olsa da, Pythton yorumlayıcısının bu sınıftaki veri özniteliklerini kullanmak istediğimizi bildiğinden emin olmamız gerekir. Bu yüzden güvenli oynuyoruz… ve “self” parametresini kullanıyoruz.
İlk yönteme bakalım.
def __init__(self):
Python’daki çoğu Sınıf, bellekte bir sınıf örneği oluşturulduğunda otomatik olarak çağırılan bir __init__
fonksiyonuna sahiptir. (Bir sınıfa başvururken, bu sınıfın bir örneği [veya nesnesi] oluşturulur.) Bu yöntem genellikle başlatıcı yöntemi olarak adlandırılır. Yöntem yürütülürse, “self” parametresi nesneye otomatik olarak atanır. Veri özniteliklerini “başlatır” olduğundan, bu yönteme başlatıcı yöntemi denir. __init__ yönteminde, özniteliğin number
değerini başlangıçta 0 olarak ayarladık. Nokta gösterimini kullanarak nesne özniteliğine başvuruyoruz.
def __init__(self): self.__number = 0
self.__number = 0
satırı kısaca “nesnedeki “sayı” özniteliğinin değeri 0’dır anlamına gelir.
Bir sonraki yönteme bakalım.
def addfive(self,num): self.__number = num return self.__number + 5
Bu yöntem “addfive” olarak adlandırılır. Sınıfı kullanan programdan “num” adlı bir parametreyi kabul eder. Yöntem daha sonra bu parametrenin değerini nesnenin içindeki “number” özniteliğine atar. Yöntem daha sonra “sayı” değerine 5 ekleyerek bu fonksiyonu çağıran yere döndürür.
Üçüncü yönteme bakalım.
def multiply(self,added): self.__added = added return self.__added * 2.453
Bu yöntem bir parametre kabul eder. Parametrenin değerini “added” özniteliğine atar ve yöntemi çağıran ifadeye “added” özniteliğinin değerini 2.453 ile çarparak döndürür.
Her yöntemin adının iki alt çizgiyle başladığına dikkat etmişsinizdir. Bunu açıklayalım. Daha önce bir nesnenin yöntemler kullanarak kendi içindeki veri öznitelikleri üzerinde çalıştığından bahsetmiştir. İdeal olarak, bu veri öznitelikleri yalnızca NESNEDEKI YÖNTEMLERLE işlenebilmelidir. Dış kodun veri özniteliklerini işlemesi mümkündür. Öznitelikleri “gizlemek” için, yalnızca nesnedeki yöntemlerin bunları işleyebilmeleri için, gösterdiğimiz gibi nesne adından önce iki alt çizgi kullanırsınız. Öznitelik isminde bu iki alt çizgiyi atlarsak nesnenin dışındaki koddan düzenleme olasılığını açarız.
Az önce incelediğimiz sınıfı kullanan programa bakalım.
Yorum olmayan kodun ilk satırına dikkat edin.
import oopexample
Bu kod satırı, ayrı bir dosyaya (modüle) kaydettiğimiz sınıfı içe aktarır. Sınıflar ayrı bir dosyada olmak zorunda değildir, ancak hemen hemen her zaman böyledir ve bu nedenle modülü bu şekilde içeri almak iyi bir uygulamadır.
Bir sonraki satır:
maths = oopexample.NumChange()
Bu satır, “oopexample” adlı modülde depolanan NumChange sınıfının bir örneğini oluşturur ve örneği “matematik” adlı değişkende depolar. Sözdizimi şu şekildedir: moduladi.Classadi()
. Daha sonra ana işlevi tanımlıyoruz. Ardından, kullanıcıdan bir numara alıyoruz.
Sonraki satır, “num” değişkeninin değerini, “matematik” adlı değişkende bir örneğini depoladığımız sınıfın bir parçası olan “addfive” adlı yönteme gönderir ve döndürülen değeri “eklendi” adlı değişkende depolar. added = maths.addfive(num)
Sonraki satır, “eklendi” değişkeninin değerini, “matematik” adlı değişkende bir örneğini depoladığımız sınıfın bir parçası olan “çarp” adlı yönteme gönderir ve döndürülen değeri “multip” adlı değişkende depolar. multip = maths.multiply(added)
Sonraki satır “İşlenen değer <işlenen değer> değeridir” yazdırır. Son satır, yukarıda özetlenen adımları yürüten ana işlevi çağırır.