Python sınıflarında, temel olarak 3 farklı şekilde metot tanımı yapılabilir.
- Örnek (Instance) metotları
- Statik (
@staticmethod
) metotlar - Sınıf (
@classmethod
) metotları
self
adı verilir. Statik metotlar, kendisini çağıran sınıf veya örnek hakkında herhangi bir bilgiye
sahip değildir. Bunlar, işlevini kaybetmeden, sınıf dışında da aynı şekilde tanımlanabilir. Sınıf metotları ise, otomatik
olarak, kendisini çağıran sınıfa veya örneğin sınıfına bir referans alır. Bu argümana da geleneksel olarak cls
adı verilir.Örnek (Instance) Metotları
Python'da yeni bir sınıf tanımlandığınız, yazdığınız metotlar öntanımlı olarak, örnek (instance) metotlarıdır. Örnek metotları, ilk argüman olarak, kendisini çağıran örneğe bir referans alır. Böylece, geçerli örneğin niteliklerine erişim ve müdahale imkanı bulurlar. Aşağıdaki kodları inceleyelim;
class ikisayi(object): def __init__(self, a, b): self.a = a self.b = b def toplam(self): return self.a + self.b x = ikisayi(3,5) print(x.toplam) # 1 print(ikisayi.toplam) # 2 print(x.toplam()) # 3 print(ikisayi.toplam(x)) # 4
Programın çıktısı:
#1: <bound method ikisayi.toplam of <__main__.ikisayi object at 0x021F0390>> #2: <unbound method ikisayi.toplam> #3: 8 #4: 8 Yukarıda, görmeye alışık olduğunuz türden bir sınıf tanımımız var. Bu sınıf, iki tane sayı hakkında veri tutmak için kullanılıyor. Yine, bolca karşınıza çıkacağı gibi
__init__
başlangıç metodu var. toplam
metodu ise, normal şekilde tanımlanmış, yani bir
örnek (instance) metodu. toplam
metodumuz, her örnek metodunda olduğu gibi, zorunlu bir ilk argüman alıyor. Bu argümana, çalışma
anında oluşturulmuş bir ikisayı objesi geçirilecek. Böylece, toplam metodu, hangi objenin a
niteliğiyle b
niteliğini toplaması gerektiğini bilebilecek.Program çıktısına dikkat edersek,
x.toplam
metodunun bound method
olduğunu görüyoruz.Yani, ikisayi.toplam
metodu belirtilen adresdeki ikisayi
objesine
bağlanmış. Yani, x.toplam
metodu çağırıldığında, ikisayi.toplam
metodu, ilk argüman olarak, o adresdeki objeyi alacak.Diğer yandan, aynı metoda, sınıf üzerinde eriştiğimizde, bir
unbound method
buluyoruz.Yani, bu method, herhangi bir örneğe bağlanmamış. Dolayısıyla,
otomatik bir ilk argüman almayacak. Eğer ikisayi.toplam()
şeklinde çağırırsanız, aşağıdaki hatayı alırsınız:TypeError: unbound method toplam() must be called with ikisayi instance as first argument
#3 ve #4 numaralı ifadeler aynı çıktıyı veriyor, çünkü, teknik olarak aynı şeyler. Siz,
x.toplam()
çağırdığınızda, Python bunu kendi içinde ikisayi.toplam(x)
şekline dönüştürüyor. Statik Metotlar
Statik Metotlar, kendisini hangi sınıf veya örneğin çağırdığını bilmez. Sadece kendine verilen argümanları bilir, örnek veya sınıf metotları gibi, gizli bir ilk argüman almazlar. Bu yönden bakıldığında, bu fonksiyonun sınıf içinde yazılmasıyla, sınıf dışında yazılması arasında, hiçbir fark yoktur. Ancak, aynı modül içerisindeki birçok fonksiyonu anlamsal bütünler içinde toplamak gerektiğinde kullanılabilir. Bunları tanımlamak için, metot tanımından önce@staticmethod
dekoratörü kullanılır.Sınıf Metotları
Diğer yandan, sınıf metotları, ilk argüman olarak, kendisini çağıran sınıfa veya kendisini çağıran örneğin sınıfına mecburi/otomatik bir referans alır. Bunu o sınıfın bir örneğini oluşturmak istediğiniz durumlarda (bkz: Factory) kullanabilirsiniz. Kendisini çağıran sınıfa bir referans aldığı için, alt sınıflarda da istenildiği gibi çalışacaktır. Örneğin, diyelim ki, bir telefon numarasını temsil eden bir sınıfınız var:class TelNo(object): def __init__(self, ulkekodu, alankodu, numara): self.ulkekodu = ulkekodu self.alankodu = alankodu self.numara = numara
def str_to_telno(string): return TelNo(*string.split(" ")) mytel = str_to_telno("+90 507 7997272")
str_to_telno
fonksiyonu, verilen karakter dizisini
boşluklarından bölüp, bunlardan yeni bir TelNo objesi oluşturuyor.
Telefon numarası tutabilmek
güzel ama, bu numarayı arayabilmemiz daha da güzel olurdu. Bunun için,
TelNo'nun aranabilen bir alt sınıfını oluşturalım. class AranabilenTelNo(TelNo): def ara(self): "bu numaraya VOIP üzerinden bağlantı kur" pass # gerçekten bu fonksiyonu kodlamamı beklemiyordunuz umarım :) def str_to_aranabilentelno(string): return AranabilenTelNo(*string.split(" "))
Bu yöntemin şöyle bir sıkıntısı var. Diyelim ki, ileride, mesaj atılabilen telno, mms gönderilebilen tel no vs. gibi bir çok alt sınıf tanımlayacaksınız. Her seferinde tek tek bu dönüşüm işlemini yapmak hem yorucu olacak, hem de kodlar çorba olacak.
Buna alternatif olarak,
TelNo
objesinde, from_string
isminde bir @classmethod
tanımladığımızda, ne olduğuna bakalım;class TelNo(object): def __init__(self, ulkekodu, alankodu, numara): self.ulkekodu = ulkekodu self.alankodu = alankodu self.numara = numara @classmethod def from_string(cls, string): return cls(*string.split(" ")) class AranabilenTelNo(TelNo): def ara(self): pass mytel = TelNo.from_string("+90 507 7997272") print(type(mytel)) # 1 myaranabilentel = AranabilenTelNo.from_string("+90 507 7997272") print(type(myaranabilentel)) # 2
#1: <class '__main__.TelNo'> #2: <class '__main__.AranabilenTelNo'> Program çıktısından görebileceğiniz gibi, iki sınıfın
from_string
metotları, doğru sınıfa ait objeler oluşturuyor. Böylece,
hem alt sınıf için tekrar ayrı fonksiyon yazmak zorunda kalmadık, hem de, doğru sınıfa ait bir örnek oluşturabildik.Dikkat ettiyseniz,
@classmethod
ile tanımladığımız metotları, doğrudan sınıf üzerinden çağırdık. Halbuki, Örnek (Instance) metotlarını, sınıfın bir örneği
üzerinden çağırıyorduk. Özetle, sınıfın kendisi ile ilgili işlem yapılacak durumlarda, @classmethod
kullanabiliriz.s
Hiç yorum yok:
Yorum Gönder