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.
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.
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.
Sınıflar ile bir miktar yeni sözdizim ve anlambilim ile üç yeni nesne tipini tanıtacağız.
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.
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)
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.
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.
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!
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.
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.
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.
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
.
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.