Çok Biçimlilik (Polymorphism) Nedir?
Programlamada çok biçimlilik (polymorphism), bir fonksiyon çağrısı ya da bir metot adı gibi tek bir kod parçasının farklı tiplerdeki değerlerle çalışabilmesi ve her tipin kendi davranışını sağlamasıdır. shape.area() çağrısı bir daire için bir kareden farklı bir hesaplama çalıştırır.
Güncellendi: 24 Eylül 2026
Python'da len("hello") 5, len([4, 8, 15]) 3 ve len({"a": 1}) 1 döndürür. Üç tip üzerinde kullanılan tek bir fonksiyon adıdır ve her tip kendi yöntemiyle sayar: bir string karakterleri, bir liste öğeleri, bir sözlük anahtarları sayar. Kelime Yunancadan gelir: poly, çok, ve morph, biçim. Tek çağrı, davranışın birçok biçimi.
Çok biçimlilik nasıl çalışır
Kod bir metodu adıyla çağırır, örneğin shape.area(). O satır çalıştığında dil gerçek nesneye bakar ve area metodunu nesnenin kendi sınıfında bulur. Bu aramaya dinamik dağıtım (dynamic dispatch) denir ve tek bir satırın farklı nesneler için farklı iş yapmasını sağlayan şey budur:
Circle 3.14
Square 9
Circle 12.57
Python metodu önce nesnenin sınıfında, sonra metot çözümleme sırası (method resolution order) denen sabit bir sırayla üst sınıflarında arayarak bulur. Square sınıfının kendi area() metodu olmasaydı arama Shape.area() metoduna ulaşır ve NotImplementedError fırlatırdı; bu, her alt sınıfın kendi metodunu sağlaması gerektiğinin işaretidir.
Döngü elindekinin ne tür bir şekil olduğunu hiç kontrol etmez. Bir üçgen eklemek için kendi area() metodu olan bir Triangle sınıfı yazarsın ve döngü değişmeden çalışır. Çok biçimlilik olmasaydı döngü, her şekil için bir if isinstance(...) dalına ihtiyaç duyar ve her yeni şekil geldiğinde düzenlenirdi.
Çok biçimlilik türleri
| Tür | Diğer adı | Nasıl görünür | Hangi sürümün seçildiği ne zaman belirlenir |
|---|---|---|---|
| Alt tip | Çalışma zamanı çok biçimliliği, method overriding | Bir alt sınıf üst sınıfının bir metodunu değiştirir | Program çalışırken |
| Ad hoc | Overloading (aşırı yükleme) | Tek bir ad, farklı parametre tipleri için birkaç sürüm; operatör aşırı yükleme de dahil | Java ve C++'ta derleme zamanında |
| Parametrik | Generics, template'ler | Her tip için çalışan tek bir kod parçası: Java'da List<T>, C++'ta vector<T> | Derleme zamanında |
İnsanlar nesne yönelimli programlamada ayrıntı vermeden "çok biçimlilik" dediklerinde neredeyse her zaman ilk satırı kastederler: overriding ile alt tip çok biçimliliği.
Python'da üçü de kendine özgü şekilde vardır. Overriding şekiller örneğindeki gibi çalışır. + gibi operatörler ad hoc çok biçimliliktir. max() ve sorted() gibi fonksiyonlar özünde parametriktir: öğeler karşılaştırılabildiği sürece bir sayı, string ya da tarih listesi kabul ederler; list[int] gibi tip ipuçları ya da bir TypeVar bunu açıkça belirtebilir.
Java'da derleme zamanı ve çalışma zamanı çok biçimliliği
Java'da iki tür de vardır ve mülakat soruları sık sık aradaki farkı sorar:
class Animal { String sound() { return "..."; } }
class Dog extends Animal {
@Override String sound() { return "Woof"; }
}
Animal pet = new Dog();
pet.sound(); // "Woof": chosen at run time from the object
int add(int a, int b) { return a + b; }
double add(double a, double b) { return a + b; }
add(2, 3); // int version, chosen by the compiler
add(2.5, 1.0); // double version
pet değişkeninin tipi Animal, yine de Dog sürümü çalışır, çünkü seçim değişkene değil nesneye bağlıdır. İki add metodu overloading'dir: derleyici program çalışmadan önce argüman tiplerine bakarak birini seçer. Interface'ler aynı çalışma zamanı davranışını kod paylaşmadan sağlar: Comparable arayüzünü uygulayan her sınıf Collections.sort ile sıralanabilir. C++ tek bir farkla aynı şekilde çalışır: bir metot yalnızca virtual olarak tanımlanmışsa çalışma zamanı dağıtımı alır. Bkz. Java'da çok biçimlilik, method overloading ve C++ virtual fonksiyonlar.
Python'da çok biçimlilik: duck typing ve operatörler
Python ortak bir üst sınıf gerektirmez. Bir nesne kodun çağırdığı metoda sahipse çalışır: "ördek gibi yürüyor ve ördek gibi vaklıyorsa ördektir". Operatörler de çok biçimlidir. a + b yazmak a.__add__(b) çağırır; böylece kendi sınıfların +, len() ve print() destekleyebilir:
3 abcd [1, 2]
Vector(11, 22)
5 3 2
Kalıtım çok biçimlilik elde etmenin bir yoludur, bir zorunluluk değil. Vector özel hiçbir şeyden kalıtım almaz, yine de len() ve + ona yerleşik bir tip gibi davranır. Python kalıtım dokümanı alt sınıf yolunu gösterir.
Sık yapılan hatalar
Python'un imzaya göre overloading yapmasını beklemek. Aynı adla yazılan ikinci bir def ilkinin yerini sessizce alır:
Hi Ana Silva
Traceback (most recent call last):
...
TypeError: greet() missing 1 required positional argument: 'last'
Bunun yerine varsayılan bir argüman kullan: def greet(first, last="").
C++'ta virtual yazmayı unutmak. O olmadan, taban sınıfa işaret eden bir pointer üzerinden bir metot çağırmak, nesne bir alt sınıf olsa bile taban sürümü çalıştırır.
Anlamı değiştiren override'lar. Bir alt sınıftaki area() çevreyi döndürürse area() metoduna güvenen her çağıran bozulur. Bir override, üst sınıfın verdiği sözü tutmalıdır; bu kural Liskov yerine geçme ilkesi (Liskov substitution principle) olarak bilinir.
Her yerde tip kontrolü. Bir if type(x) == ... dalları zinciri genellikle her tipin bunun yerine kendi metodunu taşıması gerektiğinin işaretidir.
Sırada ne var
Çok biçimlilik, her nesnenin verisini koruyan kapsülleme ve tiplerin uyguladığı ortak arayüzü tanımlayan soyutlama ile birlikte çalışır. Overriding'i Python sınıfları dokümanında pratik et ya da overloading ile overriding'in yan yana göründüğü Java kursunu dene.
Sıkça Sorulan Sorular
Çok biçimliliğe bir örnek verir misin?
+ operatörü: 1 + 2 sayıları toplar, "ab" + "cd" string'leri birleştirir, [1] + [2] listeleri birleştirir. Aynı sembol üç tip üzerinde çalışır ve ne anlama geldiğine her tip kendisi karar verir. Nesne yönelimli kodda klasik örnek, her birinin area() çağrısına kendi formülüyle cevap verdiği bir şekiller listesidir.Çok biçimlilik ile kalıtım arasındaki fark nedir?
Biyolojide polimorfizm nedir?
Python method overloading destekler mi?
def ilkinin yerini alır. Python kodu aynı etkiyi varsayılan argümanlarla, *args ile ya da ilk argümanın tipine göre bir fonksiyon seçen functools.singledispatch ile elde eder.Çok biçimlilik neden faydalıdır?
shape.draw() çağıran bir çizim programı, bir üçgen sınıfı eklediğinde hiçbir düzenleme gerektirmez; yalnızca yeni sınıf yazılır. Çok biçimlilik olmasaydı o döngü her tip için yeni bir if dalıyla büyürdü.