Python 3'te Sınıflara Çok Biçimlilik (Polymorphism) Nasıl Uygulanır?
Giriş
Çok biçimlilik, aynı arayüzün farklı temel formlar (örneğin, veri tipleri veya sınıflar) için kullanılabilme yeteneğidir. Bu, fonksiyonların farklı zamanlarda farklı türden varlıkları kullanmasına olanak tanır. Python'da nesne yönelimli programlama için bu, belirli bir sınıfa ait bir nesnenin, sanki başka bir sınıfa ait bir nesneymiş gibi aynı şekilde kullanılabileceği anlamına gelir. Çok biçimlilik, esneklik ve gevşek bağlılık (loose coupling) sağlar, böylece kod zamanla kolayca genişletilebilir ve sürdürülebilir hale gelir. Bu öğreticide, Python'da sınıflara çok biçimliliğin nasıl uygulanacağını inceleyeceğiz.
Çok Biçimlilik Nedir?
Çok biçimlilik, Python'daki sınıf tanımında önemli bir özelliktir ve sınıflar veya alt sınıflar arasında ortak olarak adlandırılan metodlar bulunduğunda kullanılır. Bu, fonksiyonların bu çok biçimli sınıflardan herhangi bir nesneyi, sınıflar arasındaki farkların farkında olmadan kullanmasına olanak tanır. Çok biçimlilik, kalıtım yoluyla gerçekleştirilebilir ve alt sınıflar temel sınıfın metodlarını kullanabilir veya bunları geçersiz kılabilir. Python’un dinamik yazımın (dynamic typing) özel bir durumu olan "ördek tipi" (duck typing), geç bağlama (late binding) ve dinamik yönlendirme (dynamic dispatch) gibi çok biçimlilik özelliklerini içerir. "Duck typing" terimi, yazar James Whitcomb Riley’nin şu sözünden türetilmiştir: “Eğer bir kuş ördek gibi yürüyorsa, ördek gibi yüzüyorsa ve ördek gibi vaklıyorsa, ben o kuşa ördek derim.” Bu kavram, bir nesnenin belirli bir amaç için uygunluğunu belirlemeye yöneliktir. Normal yazımda bu uygunluk yalnızca nesnenin tipiyle belirlenirken, ördek tipinde uygunluk, nesnenin tipinden ziyade sahip olduğu metodlar ve özelliklerle belirlenir. Yani, nesnenin ördek gibi vaklayıp vaklamadığına ve ördek gibi yürüyüp yürümediğine bakılır, nesnenin bir ördek olup olmadığına değil. Birden fazla sınıf veya alt sınıf aynı metod adlarına, ancak bu metodlar için farklı uygulamalara sahip olduğunda, bu sınıflar çok biçimlidir. Çünkü farklı türden varlıklarla kullanılabilecek tek bir arayüzü kullanırlar. Bir fonksiyon, hangi sınıfların çağrıldığını bilmeden bu çok biçimli metodları değerlendirebilir.
Çok Biçimli Sınıflar Oluşturma
Çok biçimliliği kullanmak için, iki farklı sınıf ve iki farklı nesne oluşturacağız. Bu farklı sınıfların, çok biçimli olarak kullanılabilmeleri için ortak bir arayüze sahip olmaları gerekir. Bu nedenle, farklı ancak aynı ada sahip metodlar tanımlayacağız.
Bilgi: Bu öğreticideki örnek kodları takip etmek için, yerel sisteminizde python3
komutunu çalıştırarak bir Python etkileşimli kabuğunu açın. Ardından, örnekleri >>>
isteminin ardından ekleyerek, kopyalayarak veya düzenleyerek çalıştırabilirsiniz.
Bir Köpekbalığı
(Kopekbaligi) sınıfı ve bir Palyaço Balığı
(PalyacoBaligi) sınıfı oluşturacağız. Her bir sınıf, yuz()
, geriye_yuz()
, ve iskelet()
metodlarını tanımlayacak.
polimorfik_balik.py
class Kopekbaligi():
def yuz(self):
print("Köpekbalığı yüzüyor.")
def geriye_yuz(self):
print("Köpekbalığı geriye yüzemez, ancak geriye batabilir.")
def iskelet(self):
print("Köpekbalığının iskeleti kıkırdaktan oluşur.")
class PalyacoBaligi():
def yuz(self):
print("Palyaço balığı yüzüyor.")
def geriye_yuz(self):
print("Palyaço balığı geriye yüzebilir.")
def iskelet(self):
print("Palyaço balığının iskeleti kemikten oluşur.")
Yukarıdaki kodda, Köpekbalığı
ve PalyaçoBalığı
sınıflarının ortak üç metoda sahip olduğunu görüyoruz. Ancak, bu metodların her bir sınıftaki işlevsellikleri farklıdır.
Bu sınıfları iki nesneye örneklendirelim:
polimorfik_balik.py
...
samet = Kopekbaligi()
samet.iskelet()
can = PalyacoBaligi()
can.iskelet()
Python’da python polimorfik_balik.py
komutunu çalıştırdığımızda, her nesnenin beklediğimiz gibi davrandığını görebiliriz:
Çıktı:
Köpekbalığının iskeleti kıkırdaktan oluşur.
Palyaço balığının iskeleti kemikten oluşur.
Artık ortak bir arayüzü kullanan iki nesnemiz olduğuna göre, bireysel türlerinden bağımsız olarak bu iki nesneyi aynı şekilde kullanabiliriz.
Sınıf Metodlarıyla Çok Biçimlilik
Python’un bu farklı sınıf türlerini aynı şekilde nasıl kullanabileceğini göstermek için, önce bir nesne demeti üzerinde yineleme yapan bir for döngüsü
oluşturalım. Ardından, her nesnenin hangi sınıf türüne ait olduğuna aldırış etmeden metodları çağırabiliriz. Sadece bu metodların her bir sınıfta var olduğunu varsayacağız.
polimorfik_balik.py
...
samet = Kopekbaligi()
can = PalyacoBaligi()
for balik in (samet, can):
balik.yuz()
balik.geriye_yuz()
balik.iskelet()
Burada iki nesneye sahibiz: Köpekbalığı sınıfından samet
, ve PalyaçoBalığı
sınıfından can
. for döngüsü bu nesneler üzerinde yinelenerek her biri için yuz(), geriye_yuz() ve iskelet() metodlarını çağırır.
Programı çalıştırdığımızda şu çıktıyı elde ederiz:
Çıktı:
Köpekbalığı yüzüyor.
Köpekbalığı geriye yüzemez, ancak geriye batabilir.
Köpekbalığının iskeleti kıkırdaktan oluşur.
Palyaço balığı yüzüyor.
Palyaço balığı geriye yüzebilir.
Palyaço balığının iskeleti kemikten oluşur.
for döngüsü önce samet
nesnesini (Köpekbalığı sınıfı)
, ardından can
nesnesini (PalyaçoBalığı sınıfı)
yineledi. Bu yüzden önce Köpekbalığı sınıfıyla ilgili metodlar, ardından PalyaçoBalığı sınıfıyla ilgili metodlar çağrıldı.
Bu, Python’un metodları, bu nesnelerin hangi sınıfa ait olduğunu bilmeden veya umursamadan kullandığını gösterir. Yani, metodları çok biçimli bir şekilde kullanıyoruz.
Bir Fonksiyonla Çok Biçimlilik
Herhangi bir nesneyi kabul edebilen bir fonksiyon yaratarak çok biçimliliği gösterebiliriz.
Bir okyanusta()
fonksiyonu oluşturalım ve bir balik
nesnesi almasını sağlayalım. Burada balik adını kullansak da, fonksiyon herhangi bir örneklenmiş nesneyi alabilir:
polimorfik_balik.py
...
def okyanusta(balik):
Daha sonra, bu fonksiyonun aldığı balik
nesnesini kullanarak bir şeyler yaptırmasını sağlayacağız. Bu durumda, Köpekbalığı ve PalyaçoBalığı sınıflarında tanımlanan yuz() metodlarını çağıracağız:
polimorfik_balik.py
...
def okyanusta(balik):
balik.yuz()
Sonrasında, eğer daha önce oluşturmadıysak, hem Köpekbalığı hem de PalyaçoBalığı sınıflarından örnekler oluşturup bu fonksiyonla çağırabiliriz:
polimorfik_balik.py
...
def okyanusta(balik):
balik.yuz()
samet = Kopekbaligi()
can = PalyacoBaligi()
okyanusta(samet)
okyanusta(can)
Programı çalıştırdığımızda şu çıktıyı alırız: Çıktı:
Köpekbalığı yüzüyor.
Palyaço balığı yüzüyor.
Fonksiyonu tanımlarken rastgele bir nesne (balik
) alsak da, bu nesneyi Köpekbalığı ve PalyaçoBalığı sınıflarından örneklerle etkili bir şekilde kullandık. can
nesnesi PalyaçoBalığı sınıfındaki yuz() metodunu çağırdı, samet
nesnesi ise Köpekbalığı sınıfındaki yuz() metodunu çağırdı.
Sonuç
Çok biçimlilik sayesinde, farklı nesnelerin aynı şekilde fonksiyonları ve metodları kullanmasına izin vermek, Python’un bu özelliğini kullanarak nesne yönelimli kodunuzun esnekliğini ve genişletilebilirliğini artırır.
Lisa Tagliaferri tarafından yazılan How To Apply Polymorphism to Classes in Python 3 Program makalesinin düzenlenmiş çevirisi.
Daha Fazla Oku:
- Sonraki Makale: Python Hata Ayıklayıcıyı Kullanma
- Önceki Makale: Python 3'te Sınıf Mirasını Anlamak