Altblümler

 
9. Sınıflar

Python'un sınıf mekanizması dile minimum yeni sözdizim ile sınıflar ekler. Bu C++ ve Modula-3 sınıf mekanizmalarının bir karışımıdır. Modüllerde de olduğu gibi Python'da sınıflar tanım ile kullanıcı arasına mutlak bir sınır koymaz. Miras mekanizması birden fazla temel sınıf kullanabilir. Türetilimiş sınıflar temel sınıfın metodlarını geçeriz kılabilir ve kendi sınıf metodlarından temel sınıf metodlarını çağırabilirler. Nesneler herhangi miktarda özel veri içerebilirler.

C++ terminolojisi ile söylemek gerekirse, tüm sınıf üyeleri (veri üyeleri de dahil) ``public'' ve tüm üye fonksiyonlar ``virtual'' kabul edilir. Hiçbir özel constructor/destructor yoktur. Smalltalk dilinde olduğu gibi sınıfların kendileri de nesnedir. Python'da bütün veri tipleri nesnedir aslında. C++ veya Modula-3 dillerinden farklı olarak yerleşik (built-in) veri tipleri kullanıcı tarafından geliştirilmek üzere başka sınıflar için temel sınıf olarak kullanılamazlar. Ayrıca, çoğu yerleşik işleçler sınıf gerçeklemeleri için yeniden tanımlanabilirler.

 
9.1 Terminoloji üzerine

Yaygın kabul gören sınıf terminolojisini bilmediğimden, arada sırada Smalltalk ve C++ terimleri kullanacağım. Aslında, nesne yönelimi açısından Python'a daha çok benzeyen Modula-3 dili terimlerini kullanırdım; fakat bu dilden haberdar olan okuyucuların azınlıkta olduğunu sanıyorum.

Burada nesne tabanlı programlama ile ilgilenen okuyucuların dikat etmesi gereken terminolojik bir sorun var: Python'da ``nesne'' kelimesi her zaman bir sınıf gerçeklemesi anlamına gelmez. C++ ve Modula-3 dillerinde olduğu gibi, Python'da da bütün veri tipleri sınıf değildir. Örneğin tamsayılar, listeler ve hatta dosyalar gibi daha egzotik veri tipleri bile sınıf değildir. Buna rağmen,tüm Python veri tipleri anlambilim açısından en iyi ``nesne'' kelimesi ile tanımlanabilecek benzerliklere sahiptirler.

Nesnelerin bireyselliği vardır ve birden fazla etki alanında birden fazla isim aynı nesneye bağlı olabilir. Bu diğer dillerde yansılama (aliasing) olarak bilinir. İlk bakışta Python'un bu özelliği pek beğenilmez, ve değiştirilemeyen (immutable) temel veri tipleri ile uğraşılırken bu güvenle ihmal edilebilir. Yansılama listeler ve sözlükler gibi değiştirilebilir nesneler ile program dışındaki unsurları ifade eden diğer tipler (dosyalar, pencereler vs.) içeren Python kodlarının anlamı üzerinde etkilidir. Bu genellikle programın yararına kullanılır; çünkü yansılar bazı açılardan işaretçilere ( pointer) benzerler. Örneğin, bir nesne geçirildiğinde sadece bir işaretçi geçirilmiş olur; ve bir fonksiyon kendisine argüman olarak geçirilen bir nesnede değişiklikler yaparsa fonksiyonu çağıran da değişiklikleri görür. Bu durum Pascal'daki gibi iki farklı argüman geçirme mekanizmasına duyulan ihtiyacı ortadan kaldırır.

 
9.2 Python Etki ve İsim Alanları

Sizi sınıflar ile tanışmadan önce, biraz da Python'un etki alanı kurallarından bahsetmem gerek. Sınıf tanımlamaları tam olarak neler olduğunu anlamak için etki ve isim alanlarının nasıl çalıştığını bilmeniz gerek. Bu konudaki bilgiler ileri seviyedeki her Python programcısı için yaralıdır.

Birkaç tanım ile işe koyulalım.

Bir isim alanı isimler ile nesnelerin eşleşmesidir. Çoğu isim alanları şu anda Python sözlükleri olarak kodlanmışlardır, fakat bu hiçbir şekilde fark edilmez ve gelecekte değiştirilebilir. İsim alanlarına örnekler: yerleşik isimler kümesi (abs() gibi fonksiyonlar ve yerleşik istisna isimleri vs.),bir modül içindeki global isimler ve bir fonksiyon çağrısındaki yerel isimler. Bir nesnenin özellikleri kümesi de bir isim alanıdır. İsim alanlarına ilişkin bilinecek önemli şey farklı isim alanlarındaki isimlerin birbirileri ile hiçbir ilişkisi olmadığıdır. Örneğin, iki farklı modül karışıklık yaratmadan ``maksimize'' adlı birer fonksiyon tanımlayabilir; kullanıcılar bu fonksiyonları önlerine modül adını ekleyerek kullanırlar.

Bu arada, bir noktadan sonra yazılan her herhangi bir isim için özellik kelimesini kullanıyorum. Örneğin, z.real ifadesinde real z nesnesinin bir özelliğidir. Mödül içindeki ismilere atıflar da özellik atıflarıdır: modulAdi.fonkAdi ifadesinde modulAdi bir modül nesnesidir ve fonkAdi bunun bir özelliğidir. Bir modülün özellikleri ile içinde tanımlı global değişkenler aynı isim alanını paylaşırlar. 9.1

Özelikler salt okunur veya yazılabilir olabilirler. Yazılabilir oldukları durumda özelliklere atama yapmak mümkündür. Modül özellikleri yazılabilirdir: "modulAdi.sonuc = 42" gibi bir ifade kullanabilirsiniz. Yazılabilir özellikleri del deyimini kullanarak silmek de mümkündür. Örneğin "del modulAdi.sonuc"ifadesi modulAdi nesnesinden sonuc isimli özelliği siler.

Farklı anlarda yaratılan isim alanlarının farklı ömürleri olur. Yerleşik isimleri içeren isim alanı Python yorumlayıcısı çalıştırıldığında yaratılır ve asla silinmez. Bir modüle ait global isim alanı modül tanımı okunduğunda yaratılır ve genellikle yorumlayıcı çalıştığı sürece silinmez. Yorumlayıcının bir dosyadan veya etkileşimli olarak çalıştırdığı deyimler de __main__ isimli bir modüle ait kabul edilir, ve bunların da kendi global isim alanı vardır. Yerleşik (built-in) isimler de __builtin__ isimli bir modülde yaşarlar.

Bir fonksiyona ait yerel isim alanı fonksiyon çağırıldığında yaratılır, ve fonksiyondan dönüldüğünde veya fonksiyon içinde ele alınmamış bir istisna gerçekleştiğinde silinir. Tabi ki Özyinelemeli ( recursive) çağrıların herbiri kendi yerel isim alanına sahiptir.

Bir etki alanı bir isim alanının doğrudan erişilebildiği bir metin bölgesidir. Burada ``doğrudan erişilebilir'' ifadesini anlamı yetersiz bir isim atfının isim alanında isim bulmaya teşebbüs etmesidir.

Etki alanları statik olarak belirlenmelerine rağmen, dinamik olarak kullanılırlar. İcranın herhangi bir anında isim alanlarına doğrudan erişilebilen iç içe geçmiş en az üç etki alanı vardır: ilk aranan ve yerel isimleri içeren en iç etki alanı; en yakın olanından başlanarak aranan çevreleyen fonksiyonların isim alanları; daha sonra aranan ve o andaki modülün global değişkenlerini içeren orta etki alanı; ve yerleşik isimlerin bulunduğu isim alanı olan en dış etki alanı (en son aranır).

Eğer bir isim global olarak tanımlanmış ise tüm atıflar ve atamalar doğrudan modülün global isimlerini barındıran orta etki alanına giderler. Aksi takdirde, en iç etki alanının dışındaki tüm isimler salt okunurdur.

Genellikle yerel etki alanı o an içinde bulunulan (program metninde) fonksiyonun yerel isimlerine atıfta bulunur. Fonksiyonların dışında yerel etki alanı global etki alanı ile aynı isim alanıdır: modülün isim alanı. Sınıf tanımlamaları da yerel etki alanı içerisine bir başka isim alanı daha eklerler.

Etki alanlarını metne bağlı olarak belirlendiğini anlamak önemlidir. Bir modül içinde tanımlı bir fonksiyonun global etki alanı o modülün isim alanıdır; nereden çağırıldığı ya da hangi farklı isim ile çağırıldığı bir fark yaratmaz. Diğer yandan, asıl isim araması icra anında dinamik olarak yapılır; ancak dilin tanımı ``derleme'' sırasında yapılan statik isim çözümlemeye doğru değişmektedir ve dinamik isim çözümlemeye güvenmemelisiniz ! Örneğin, yerel değişkenler şu anda statik olarak belirlenmektedir.

Python'a özgü bir tuhaflık da atamaların her zaman en iç etki alanına gitmesidir. Atamalar veri kopyalamaz; sadece nesnelere isimler bağlarlar. Aynı şey silme işlemleri için de geçerlidir: "del x"ifadesi x'in yerel etki alanı tarafından atfedilen isim alanındaki bağını kaldırır. Aslında, yeni isimler yaratan tüm işlemler yerel etki alanını kullanırlar. Fonksiyon tanımları ve import deyimleri modül veya fonksiyon adını yerel etki alanına bağlarlar. Bir değişkenin global etki alanında bulunduğunu belirtmek için global deyimi kullanılabilir.

 
9.3 Sınıflara İlk Bakış

Sınıflar ile bir miktar yeni sözdizim ve anlambilim ile üç yeni nesne tipini tanıtacağız.

 
9.3.1 Sınıf Tanımlama

Sınıf tanımlamanın en basit şekli şöyledir:

class SinifAdi:
    <deyim-1>
    .
    .
    .
    <deyim-N>

Sınıf tanımlamalarının, fonksiyon tanımlamalarında (def deyimleri) olduğu gibi, etkin olmaları için önce işletilmeleri gerekir. (Yanlışlıkla sınıf tanımlarını if deyimleri veya fonksiyon içlerine koymamaya dikkat edin.)

Pratikte bir sınıf tanımının içindeki deyimler genellikle fonksiyon tanımları olur; fakat başka deyimler de kullanmak mümkün ve yararlıdır (buna daha sonra yine değineceğiz). Sınıf içindeki fonksiyon tanımlarının argüman listesi kendilerine özgü bir şekle sahiptir; ancak buna da daha sonra değineceğiz.

Bir sınıf tanımına girildiğinde yeni bir isim alanı (name space) oluşturulur ve bu yerel etki alanı (scope) olarak kullanılır. Yerel değişkenlere yapılan bütün atamalar bu yeni isim alanına gider. Yeni tanımlanan fonksiyonların isimleri de buraya eklenir.

Bir sınıf tanımı normal olarak tamamlandığında bir sınıf nesnesi yaratılmış olur. Bu, temel olarak, sınıf tanımının oluşturduğu isim alanı etrafında bir örtüdür. Sınıf nesnelerini bir sonraki bölümde daha yakından tanıyacağız. Orijinal etki alanı (sınıf tanımına girilmeden önce etkin olan) yine eski yerini alır ve sınıf nesnesi de buna sınıf tanımında kullanılan isim (örnekteki SinifAdi) ile dahil olur.

 
9.3.2 Sınıf Nesneleri

Sınıf nesneleri iki tür işlemi destekler: özelliklere değinme ( attribute reference) ve sınıfın gerçeklenmesi (instantiation).

Özlliklere değinmek için Python'da bütün özelliklere erişmek için kullanılan standart sözdizim kullanılır: nesne.isim. Kullanılabilecek özellik isimleri sınıf nesnesi yaratılırken sınıfın isim alanında bulunan bütün isimledir. Sınıf tanımımız aşağıdaki gibi ise:

class benimSinif:
    "Basit bir sınıf örneği."
    i = 12345
    def f(self):
        return 'Merhaba'

benimSinif.i ve benimSinif.f bir tamsayı ve bir metod nesnesi geri döndüren geçerli özellik atıflarıdır. Sınıf özelliklerine atama yapmak da mümkündür. Örneğin atama yoluyla benimSinif.i değeri değiştirilebilir. Ayrıca, __doc__ da geçerli bir özellik olup sınıfa ait belgeleme karakter dizisini geri döndürür: "Basit bir sınıf örneği.".

Sınıfın gerçeklenmesi fonksiyon notasyonunu kullanır. Sınıf nesnesini yeni bir sınıf gerçeklemesi geri döndüren parametresiz bir fonksiyonmuş gibi düşünebilirsiniz. Örneğin yukarıda tanımladığımız sınıf için:

x = benimSinif()

Yeni bir sınıf gerçeklemesi oluşturur ve bu nesneyi x yerel değişkenine atar.

Gerçekleme işlemi(bir sınıf nesnesini ``çağırmak'') boş bir nesne yaratır. Pek çok sınıf nesneleri bilinen bir ilk durumda yaratmak ister. Bu yüzden bir sınıf __init__() adlı özel metodu şu şekilde tanımlayabilir:

    def __init__(self):
        self.data = []

Bir sınıfın __init__() metodu tanımlanmış ise gerçeklenme işlemi yeni sınıf gerçeklemesi için bu metodu otomatik olarak çağırır.

Daha fazla esneklik için __init__() metodunun argümanları da olabilir. Bu durumda sınıfın gerçeklenmesinde kullanılan argümanlar __init__() metoduna geçirilir. Örnek:

>>> class karmasikSayi:
...     def __init__(self, gercekKsm, sanalKsm):
...         self.g = gercekKsm
...         self.s = sanalKsm
...
>>> x = karmasikSayi(3.0, -4.5)
>>> x.g, x.s
(3.0, -4.5)

 
9.3.3 Nesneler (Gerçeklenen Sınıflar)

Nesneler ile ne yapabiliriz ? Bunlar ile yapabileceğimiz tek şey özellikleri ile uğraşmaktır. Nesnelerin iki tür özellikleri vardır.

Bunların ilki veri özellikleridir. Veri özelliklerinin tanımlanmış olması gerekmez; yerel değişkenlerde olduğu gibi bunlar da kendilerine ilk atama yapıldığında var olurlar. Örneğin x yukarıda tanımlanan benimSinif sınıfının bir gerçeklemesi olduğunu düşünürsek aşağıdaki program parçası 16 değerini geride bir iz bırakmadan yazdırır:

x.sayac = 1
while x.sayac < 10:
    x.sayac = x.sayac * 2
print x.sayac
del x.sayac

Nesnelerin ikinci tür özellikleri de metodlardır. Metod bir sınıfa ``ait olan'' bir fonksiyondur. Python dilinde metodlar sınıf gerçeklemelerine özgü değildir; diğer nesne türlerinin de metodları vardır (listeler, sözlükler vs.). Aşağıda metod terimini, aksi belirtilmediği sürece, sadece sınıf gerçeklemelerinin metodları anlamında kullanacağız.

Bir nesneye ilişkin geçerli özellik isimleri bunun sınıfına bağlıdır. Tanıma göre fonksiyon olan tüm sınıf özellikleri o nesnenin metodları olur. Bu yüzden örnek sınıfımız için x.f geçerli bir metod atfıdır, çünkü benimSinif.f bir fonksiyondur fakat x.i değildir çünkü benimSinif.i değildir. Burada şuna dikkat edelim: x.f ile benimSinif.f aynı şey değildir.

 
9.3.4 Metod Nesneleri

Genellikle bir metod şu şekilde doğrudan çağırılır:

x.f()

Bizim örneğimizde bu 'Merhaba' karakter dizisini geri döndürür. Bir metodu doğrudan çağırmak şart değildir: x.f bir metod nesnesidir ve saklanıp daha sonra çağırılabilir. Örneğin:

xf = x.f
while True:
    print xf()

sonsuza kadar "'Merhaba'" yazdırır.

Bir metod çağırıldığında tam olarak ne olur ? x.f() çağırılırken bir argüman kullanılmadığı halde f fonksiyon tanımında bir argüman kullanıldığını fark etmişsinizdir. Argümana ne oldu acaba ? Şüphesiz, Python argüman gerektiren bir fonksiyon argümansız çağırıldığında bir istisna oluşturur.

Cevabı belki de tahmin ettiniz: metodlar fonksiyonun ilk argümanı olarak nesneyi alırlar. Örneğimizdeki x.f() çağrısı aslında benimSinif.f(x) ile aynıdır. Genel olarak, bir metodu n elemanlı bir argüman listesi ile çağırmak, aynı fonksiyonu başına metod nesnesinin eklendiği argüman listesi kullanarak çağırmak ile aynı şeydir.

 
9.4 Rasgele Açıklamalar

Veri özellikleri aynı isimli metod özelliklerini bastırırlar. Büyük programlardaki zor fark edilen isim çakışması hatalarından kaçınmak için çakışmaları en aza indirecek bir isimlendirme yöntemi kullanmak akıllıca olur. Metod isimleri büyük harf ile başlatılırken, veri isimleri özel bir karakter (alt çizgi gibi) ile başlatılabilir. Metodlar için fiil ve veri yapıları için isim olan kelimeler kullanılabilir.

Veri özelliklerine o nesnenin kullanıcıları (``istemcileri'') atıfta bulunabileceği gibi, metodlar da bunlara atıfta bulunabilirler. Başka bir deyişle, sınıflar tamamen soyut veri tipleri oluşturmak için kullanılamazlar. Aslında, Python'da hiçbir şey veri saklamayı zorlamayı mümkün kılmaz.

Kullanıcılar nesnelerin veri özelliklerini dikkatli kullanmalılar; çünkü kullanıcılar metodlar tarafından kullanılan önemli değişkenlere atama yaparak istenmeyen hatalara sebep olabilirler. Kullanıcıların, isim çakışmalarından kaçındıkları sürece, bir nesneye metodlarının geçerliliğini etkilemeden kendi veri özelliklerini ekleyebileceklerine dikkat edin.

Metod içlerinden veri özeliklerine (ya da diğer metodlara !) atıfta bulunmanın kestirme bir yolu yoktur. Bunun aslında metodların okunabilirliğini artırdığını düşünüyorum; bir metoda göz attığınızda yerel değişkenler ile nesne değişkenlerini birbirilerine karıştırma şansı yoktur.

Usul olarak metodların ilk argümanına self adı verilir. Bu tamamen usule dayanır; self isminin Python için kesinlikle hiç bir özel anlamı yoktur. Bu usule uymazsanız programınız diğer Python programcıları tarafından daha zor okunur ve sınıf tarayıcısı ( class browser) programları da bu usule dayanıyor olabilirler.

Sınıf özelliği olan her fonksiyon o sınıfın nesneleri için bir metod tanımlar. Fonksiyon tanımının sınıf tanımı içerisinde geçmesi şart değildir; fonksiyon nesnesini sınıf içindeki yerel bir değişkene atamak da mümkündür. Örneğin:

# Sınıf dışında tanımlanmış fonksiyon
def f1(self, x, y):
    return min(x, x+y)

class C:
    f = f1
    def g(self):
        return 'Merhaba'
    h = g

Şimdi f, g ve h'ın hepsi C sınıfının özellikleri oldular ve aynı anda C sınıfının nesnelerinin metodlarıdırlar (h ve g birbirinin tamamen aynısıdır). Bu tür uygulamanın genellikle sadece okuyucunun kafasını karıştırmaya yaradığına dikkat edin.

Metodlar self argümanının metod olan özelliklerini kullanarak diğer metodları çağırabilirler:

class Bag:
    def __init__(self):
        self.data = []
    def add(self, x):
        self.data.append(x)
    def addtwice(self, x):
        self.add(x)
        self.add(x)

Metodlar sıradan fonksiyonların yaptığı şekilde global değişkenlere atıfta bulunabilirler. Bir metoda ilişkin global etki alanı (scope) sınıf tanımının bulunduğu modüldür. Sınıfın kendisi asla gobal etki alanı olarak kullanılmaz. Bir metod içinde global veri kullanmak için ender olarak iyi bir sebep olduğu halde, global etki alanı kullanımının pek çok mantıklı sebebi vardır. Örneğin, global etki alanına yüklenmiş fonksiyon ve modülleri, metodlar ve bunun içinde tanımlanmış diğer fonksiyon ve sınıflar kullanılabilir. Genellikle metodu içeren sınıfın kendisi bu global etki alanı içinde tanımlanmıştır ve bir sonraki kısımda bir metodun kendi sınıfına atıfta bulunmak istemesi için birkaç iyi sebep bulacağız!

 
9.5 Miras

Tabi ki, miras alma desteği olmayan bir ``sınıf'' özelliği adına layık olmaz. Türetilmiş sınıf tanımının söz dizimi (syntax) aşağıdaki gibidir:

class turemisSinifAdi(TemelSinifAdi):
    <deyim-1>
    .
    .
    .
    <deyim-N>

TemelSinifAdi ismi türetilmiş sınıfın tanımının bulunduğu etki alanında tanımlı olmalıdır. Temel sınıf adı yerine bir ifade kullanmak da mümkündür. Bu temel sınıf adı başka bir modül içinde tanımlı olduğunda yararlıdır:

class turemisSinifAdi(modulAdi.TemelSinifAdi):

Bir türetilmiş sınıf tanımının işletilmesi bir temel sınıf ile aynıdır. Bir sınıf nesnesi yaratıldığında temel sınıf hatırlanır. Bu özellik atıflarını çözümlemede kullanılır; atıfta bulunulan özellik o sınıfta yok ise temel sınıfta aranır. Bu kural temel sınıfın kendisi de başka bir sınıftan türetildiyse özyinelemeli (recursive) olarak çağırılır.

Türetilmiş sınıftan nesne oluşturmanın özel bir tarafı yoktur: turetilmisSinifAdi() o sınıfın yeni bir nesnesini yaratır. Metod atıfları şu şekilde çözümlenirler: ilgili sınıf özelliği, gerekirse temel sınıflar zinciri taranarak, aranır ve metod atfı geçerli ise bu bir fonksiyon nesnesi verir.

Türetilmiş sınıflar temel sınıflarının metodlarını bastırabilirler. Metodlar aynı nesnenin diğer metodlarının çağırırken özel önceliklere sahip olmadıkları için aynı temel sınıfta tanımlı bir metodu çağıran temel sınıf metodu bunu bastıran bir türetilmiş sınıf metodunu çağırmış olabilir. C++ programcıları için not: Tüm Python metodları sanaldır (virtual).

Türetilmiş sınıftaki bir bastıran metod aslında temel sınıftaki metodun yerini almak yerine onu geliştirmek isteyebilir. Temel sınıf metodunu doğrudan çağırmanın basit bir yolu vardır: " temelSinifadi.metodAdi(self, argumanlar)". Bu bazen kullanıcılar için de faydalıdır. Bunun sadece temel sınıf global etki alanı içine doğrudan yüklendiyse çalıştığına dikat edin.

 
9.5.1 Çoklu Miras

Python çoklu miras almanın kısıtlı bir şeklini destekler. Birçok temel sınıfı olan bir sınıf tanımı aşağıdaki gibidir:

class turemisSinifAdi(temel1, temel2, temel3):
    <ifade-1>
    .
    .
    .
    <ifade-N>

Burada sınıf özelliği atıflarını çözümlemede kullanılan kuralı açıklamamız gerekiyor. Bir özellik turemisSinifAdi içinde bulunamazsa temel1 içinde sonra temel1'in temel sınıfları içerisinde ve burada da bulunamazsa temel2 içinde aranır vs.

Bazı kişilere temel1'den önce temel2 ve temel3 içinde arama yapmak daha doğal gelir. Bu temel1'in herhangi bir özelliğinin temel1 içinde veya bunun temel sınıflarında tanımlanmış olup olmadığını bilmenizi gerektir ki temel2 içindeki isimler ile çakışmalardan kaçınabilesiniz.

Python kazara oluşan isim çakışmalarına karşı usule güvenir ve bu yüzden çoklu kalıtımın rasgele kullanımının program bakımı yapan kişi için bir kabus olduğu açıktır. Çoklu kalıtımın iyi bilinen bir problemi aynı temel sınıfa sahip iki sınıftan türeme yapmaktır. Bu durumda ne olduğunu anlamak kolaydır; ancak bunun ne işe yarayacağı pek açık değildir.

 
9.6 Özel Değişkenler

Sınıfa özel tanımlayıcılar (identifier) için sınırlı destek vardır. __spam formundaki (en az iki ön alt çizgi ve en fazla bir alt çizgi son eki) belirteç _sinifadi__spam şeklini alır. Burada sinifadi o anki sınıf adının alt çizgileri atılmış olan halidir. Bu değişiklik tanımlayıcının sözdizimsel konumuna bakılmaksızın yapılır ki bu sınıfa özel değişkenler yaratılabilsin. Değiştirilen tanımlayıcı 255 karakteri aşarsa kırpılabilir. Sınıflar dışında veya sınıf adı sadece alt çizgilerden oluşuyorsa kırpma olmaz.

İsim değiştirmenin amacı sınıflara, türemiş sınıflarca tanımlanan nesne değişkenlerini dert etmeden veya sınıf dışındaki nesne değişkenleri ile uğraşmadan, kolayca özel nesne değişkenleri ve metodlar tanımlama yolu sağlamaktır. Değiştirme kurallarının genelde kazaları önlemeye yönelik olduğuna dikkat edin; ancak yine de buna niyet eden kişi özel değişkenlere ulaşıp bunları değiştirebilir. Bu bazı özel durumlarda kullanışlı da olabilir.

exec, eval() veya evalfile() fonksiyonlarına geçirilecek kod çağıran sınıf adının o anki sınıf adı olduğunu düşünmez; bu da ``bayta derlenmiş'' kod ile sınırlı global deyiminin etkisine benzer. Aynı kısıtlama getattr(), setattr() ve delattr() fonksiyonları için ve doğrudan atfedildiğinde __dict__ için de mevcuttur.

 
9.7 Öteberi

Bazen Pascal'daki ``record'' veya C'deki ``struct'' benzeri bir veri tipi birkaç veriyi bir arada toplamak için yaralı olabilir. Boş bir sınıf tanımı bu iş için yeterlidir:

class Eleman:
    pass

ali = Eleman() # Boş bir eleman kaydı yarat

# Kaydın alanlarını doldur
ali.isim = 'Ali Veli'
ali.bolum = 'Muhasebe'
ali.maas = 1000000

Soyut bir veri tipi bekleyen Python koduna o veri tipinin metodlarını emüle eden bir sınıf geçirilebilir. Örneğin bir dosya nesnesinden bir miktar veriyi formatlayan bir fonksiyonunuz varsa, read() ve readline() metodları olan ve veriyi bir karakter dizisinden alan bir sınıfı o fonksiyona argüman olarak geçirebilirsiniz.

Gerçekleme metodu nesnelerinin de kendi özellikleri var: metodun gerçeklemesi olduğu nesne metod.im_self ve o metoda karşılık gelen fonksiyon metod.im_func.

 
9.7.1 İstisnalar Sınıf Olabilir

Kullanıcı tanımlı istisnalar artık karakter dizisi olmakla sınırlı değiller; sınıf da olabilirler. Bu mekanizmayı kullanarak genişletilebilir istisna hiyerarşileri yaratılabilir.

raise deyimi için iki yeni form mevcut:

raise Sinif, gercekleme

raise gercekleme

İlk formda gercekleme Sinifa ait bir gerçekleme olmalıdır. İkinci form ise şunun kısaltmasıdır:

raise gercekleme.__class__, gercekleme

Bir except bloğu hem sınıflar hem de karakter dizileri içerebilir. Bir except bloğu içindeki sınıf eğer aynı sınıf veya bir temel sınıf ise istisna ile uyumludur. Türetilmiş sınıf içeren bir except bloğu temel sınıf ile uyumlu değildir. Örneğin aşağıdaki program B, C, D çıktısını o sırayla verir:

class B:
    pass
class C(B):
    pass
class D(C):
    pass
for c in [B, C, D]:
    try:
        raise c()
    except D:
        print "D"
    except C:
        print "C"
    except B:
        print "B"

Eğer except blokları ters sırayla yazılmış olsalardı ("except B"başta olacak şekilde) çıktı B, B, B olacaktı; çünkü uyan ilk except bloğu tetiklenecekti.

Ele alınmamış sınıf istisnası için bir mesaj yazılacağı zaman, önce sınıf adı yazılır, ardından iki nokta üst üste ve bir boşluk ve son olarak da gerçeklemenin yerleşik str() fonksiyonun geri döndürülen karakter dizisi karşılığı yazılır.



Footnotes

... paylaşırlar.9.1
Buna bir istisna: modül nesnelerinin, modülün isim alanını oluşturmada kullanılan sözlüğü oluşturan __dict__ isimli salt okunur ve gizli bir özelliği vardır. __dict__ bir özelliktir fakat global bir isim değildir.