Polimorfizm ve duck typing

Polimorfizm, farklı nesnelerin ortak bir davranış üzerinden aynı akışta kullanılabilmesidir. Python’da bunun için her zaman ortak bir üst sınıf kurmak gerekmez. Bir nesne gerekli davranışı sunuyorsa onu kullanabiliriz. Bu yaklaşım yaygın olarak duck typing olarak adlandırılır.

Bu hafta neleri yapabilmelisiniz?

  • Polimorfizmi “aynı mesaj, farklı davranış” fikriyle açıklayabilmeli,
  • Farklı sınıflardan nesneleri ortak metot üzerinden kullanabilmeli,
  • Duck typing yaklaşımını örnekleyebilmeli,
  • Gereksiz type() / isinstance() koşul zincirlerini fark edebilmeli,
  • hasattr() ile davranışın varlığını kontrol etmenin sınırını açıklayabilmeli,
  • EAFP ve LBYL yaklaşımlarını temel düzeyde ayırabilmeli,
  • Kalıtım ile polimorfizmin aynı şey olmadığını açıklayabilmeli,
  • Davranış sözleşmesinin önemini tartışabilmelisiniz.

Aynı çağrı, farklı davranış

Döngü nesnenin tam türünü bilmeden send() çağırır. Her nesne davranışı kendi biçiminde gerçekleştirir.

Farklı nesnelerin aynı metot çağrısı üzerinden farklı davranışlar sergilemesini gösteren diyagram.

Polimorfizm ve ortak arayüz

Kalıtım olmadan da polimorfizm

Yukarıdaki iki sınıf ortak bir üst sınıftan türemedi. Yine de ikisi de send(message) davranışını sunduğu için aynı akışta kullanılabildi.

Kalıtım ilişkisi zorunlu olmadan gerekli davranışı sağlayan nesnelerin aynı bağlamda kullanılabilmesini gösteren diyagram.

Duck typing

Nesnenin kim olduğundan önce, gerekli davranışı sunup sunmadığına bak.

Bu yaklaşım duck typing olarak bilinir.

Kötü sinyal: büyüyen tür zinciri

def send_notification(notification, message):
    if type(notification) is EmailNotification:
        return notification.send_email(message)
    elif type(notification) is SmsNotification:
        return notification.send_sms(message)

Yeni tür geldikçe fonksiyon değişir. Ortak davranış sunmak daha genişletilebilir olabilir:

def send_notification(notification, message):
    return notification.send(message)
Importantisinstance() kullanmak başlı başına hata değildir

Tür kontrolü sınır doğrulamasında, serileştirmede veya gerçekten türe bağlı karar gerektiğinde anlamlı olabilir. Tasarım kokusu, nesnenin kendi davranışını çağırmak yerine her yeni tür için büyüyen bir koşul zinciriyle davranış seçmektir.

hasattr() ne söyler, ne söylemez?

Bir nesnenin belirli adlı niteliğe/metoda sahip olup olmadığını hasattr() ile kontrol edebiliriz:

Ancak hasattr(obj, "send") yalnızca bu adın erişilebilir olduğunu söyler. send gerçekten çağrılabilir mi, doğru parametreleri kabul ediyor mu ve beklenen anlamı taşıyor mu sorularını tek başına çözmez. Bu yüzden duck typing’i “önce her şeyi hasattr ile kontrol et” şeklinde anlamayın.

EAFP ve LBYL

Python kodunda iki yaklaşımın adını sık görebilirsiniz:

  • LBYL — Look Before You Leap: İşlemden önce koşulu kontrol et.
  • EAFP — Easier to Ask Forgiveness than Permission: Normal işlemi dene, beklenen başarısızlığı uygun istisnayla yönet.

Örneğin LBYL:

if hasattr(notification, "send"):
    result = notification.send(message)
else:
    result = "Desteklenmiyor"

EAFP yaklaşımı:

try:
    result = notification.send(message)
except AttributeError:
    result = "Desteklenmiyor"
WarningEAFP “her şeyi except Exception ile yakala” değildir

Beklenen başarısızlığı dar biçimde yakalayın. Ayrıca AttributeError bazen send() metodunun içinde de oluşabilir; körlemesine yakalamak gerçek bir programlama hatasını yanlış yorumlayabilir. Davranış sözleşmesi açık olduğunda çoğu zaman doğrudan çağrı yapmak en sade çözümdür.

Bu kavramlar 5. haftadaki try/except bilgisini nesne arayüzleriyle birleştirir. Amaç tek bir tarzı dogma hâline getirmek değil, gereksiz ön kontroller ile hatayı fazla geniş yakalama arasındaki dengeyi görmektir.

Davranış sözleşmesi

Duck typing “her şeyi dene, çalışırsa olur” anlamına gelmez. send(message) gibi ortak davranış için giriş, dönüş değeri ve hata koşulları açık olmalıdır. Resmî bir arayüz sınıfı olmasa bile bu bir davranış sözleşmesi oluşturur.

Fonksiyonlar da polimorfik davranabilir

Farklı türler ortak protokole katıldığı için len() hepsiyle çalışır. 12. haftada kendi sınıflarımızı Python veri modeline bağlayacağız.

Polimorfizm ve kalıtım ayrımı

Kalıtım sınıflar arasındaki yapısal ilişkidir. Polimorfizm farklı nesnelerin ortak davranış üzerinden kullanılabilmesidir. Kalıtım bunu kolaylaştırabilir; ancak Python’da ortak üst sınıf zorunlu değildir.

Soyut temel sınıf (ABC) kavram radarı

from abc import ABC, abstractmethod

class Payment(ABC):
    @abstractmethod
    def pay(self, amount):
        pass

ABC, alt sınıfların belirli davranışı sunması beklentisini daha açık ifade edebilir. Bu geçiş sürümünde ABC yazmak ölçme beklentisi değildir.

Alıştırma — Koşul zincirini kaldır

Tür kontrollerini kaldırıp aynı çıktıyı ortak speak() davranışıyla üretin. Ardından Bird ekleyip ana döngünün değişmediğini gösterin.

Alıştırma — Ortak davranışı tamamla

return payment.pay(amount)

Küçük üretim görevi — Rapor çıktıları

ConsoleReport, TextReport, CompactReport sınıflarının her biri render(data) metodu sunsun. Tek bir show_report(report, data) fonksiyonuyla üçünü de kullanın. Dördüncü bir sınıf ekleyerek ana fonksiyonun değişmediğini gösterin.

Çalışır kod teslimi: Dört rapor nesnesini aynı koleksiyonda dolaştırıp render() sonuçlarını üretin. Ayrıca bir nesnede hasattr(..., "render") sonucunu gözlemleyin; sonra asıl çözümünüzün neden tür/özellik kontrol zincirine ihtiyaç duymadığını iki cümleyle açıklayın.

Kendinizi kontrol edin

  1. Polimorfizm nedir?
  2. Duck typing hangi varsayıma dayanır?
  3. hasattr() neyi garanti etmez?
  4. EAFP ile LBYL arasındaki temel fark nedir?
  5. EAFP neden except Exception demek değildir?
  6. Polimorfizm için kalıtım zorunlu mudur?
  7. Ortak üst sınıf olmaması davranış sözleşmesine ihtiyaç olmadığı anlamına gelir mi?

Bu haftadan akılda kalması gerekenler

  • Polimorfizm, ortak çağrının farklı nesnelerde farklı davranış üretmesidir.
  • Duck typing sayesinde ortak üst sınıf her zaman zorunlu değildir.
  • hasattr() yararlı bir gözlem aracıdır; davranış sözleşmesinin yerini tutmaz.
  • EAFP ve LBYL iki farklı kontrol yaklaşımıdır; beklenen hatayı dar yakalamak önemlidir.
  • Nesnenin türünü sorgulamak yerine davranışı çağırmak çoğu zaman daha esnek tasarımdır.
  • Kalıtım bir ilişki; polimorfizm bir kullanım biçimidir.
Back to top