Python, programlarınızda beklenmedik bir hatayı işlemek ve bunlarda hata ayıklama yeteneklerini eklemek için istisna işleme ve onaylama olmak üzere iki çok önemli özellik sunar. İstisna işleme standart hatalar ve yazılımcı tarafından oluşturulan hatalar olmak üzere ikiye ayrılabilir.
11.1. Standart istisnalar
Python içinde bulunan tüm hatalar Exception sınıfından türetilir. Aşağıdaki tüm hatalar ve açıklamaları bulunmaktadır.
İstisna adı | Tanımı |
---|---|
Exception | Tüm hataların temel sınıftır. |
StopIteration | Bir iterasyonun next() metodu bir nesneyi göstermediğinde oluşur. |
SystemExit | sys.exit() fonksiyonu tarafından oluşur. |
StandardError | StopIteration ve SystemExit dışındaki tüm yerleşik istisnalar için temel sınıftır. |
ArithmeticError | Sayısal hesaplamalar için ortaya çıkan tüm hatalar için temel sınıftır. |
OverflowError | Bir hesaplama, sayısal bir tür için maksimum sınırı aştığında oluşur. |
FloatingPointError | Float hesaplama başarısız olduğunda oluşur. |
ZeroDivisionError | Sıfıra bölme veya mod alma işleminde ortaya çıkar. |
AssertionError | Assert ifadesinin başarısız olması durumunda ortaya çıkar. |
AttributeError | Öznitelik referansı veya atamasının başarısız olması durumunda ortaya çıkar. |
EOFError | raw_input() veya input() fonksiyonundan girdi olmadığında ve dosyanın sonuna ulaşıldığında ortaya çıkar. |
ImportError | Bir import işlemi başarısız olduğunda oluşur. |
KeyboardInterrupt | Kullanıcı program yürütmeyi kestiğinde (genellikle Ctrl + c tuşlarına basıldığında) ortaya çıkar. |
LookupError | Tüm arama hataları için temel sınıftır. |
IndexError | Bir sıralı yapıda (list veya tüple gibi) indeks bulunmadığı zaman ortaya çıkar. |
KeyError | Bir dictionary’de belirli bir anahtar bulunmadığı zaman ortaya çıkar. |
NameError | Bir tanımlayıcı yerel veya global isim uzayında bulunmadığı zaman ortaya çıkar. |
UnboundLocalError | Bir fonksiyon veya metotta yerel bir değişkene erişmeye çalışırken ortaya çıkar, ancak bu değişkene değer atanmamıştır. |
EnvironmentError | Python çevresinin dışında ortaya çıkan tüm istisnalar için temel sınıftır. |
IOError | Var olmayan bir dosyayı açmaya çalışırken, yazdırma sırasında veya open() fonksiyonu gibi bir giriş / çıkış işlemi başarısız olduğunda ortaya çıkar. Bir anlamda işletim sistemi ile ilgili sorunlar olarak düşünülebilir. |
SyntaxError | Python sözdiziminde bir hata olduğunda oluşur. |
IndentationError | Girinti düzgün şekilde belirtilmediğinde ortaya çıkar. |
SystemError | Python yorumlayıcısı bir iç sorun bulduğunda ortaya çıkar, ancak bu hatayla karşılaşıldığında yorumlayıcı yorumlama işlemine devam eder. |
SystemExit | Python yorumlayıcısı sys.exit() fonksiyonunu kullanarak bırakıldığında ortaya çıkar. Kodda ele alınmazsa, yorumlayıcı program çalışmasını bırakır. |
TypeError | Belirtilen veri türü için geçersiz olan bir fonksiyon veya işlem denendiğinde oluşur. |
ValueError | Bir veri türü için yerleşik fonksiyon geçerli bir argüman türüne sahip olduğunda ortaya çıkar, ancak argümanların belirtilen geçersiz değerleri vardır. |
RuntimeError | Oluşturulan bir hata herhangi bir kategoriye girmediğinde oluşur. |
NotImplementedError | Kalıtımlı bir sınıfta uygulanması gereken soyut (abstract) bir yöntem gerçekte uygulanmadığında ortaya çıkar. |
11.2. Python’da onaylama
Bir onaylama, programın test edilmesini bitirdiğinizde açabileceğiniz veya kapatabileceğiniz bir mantık kontrolüdür. Bir onaylamayı oluşturmanın en kolay yolu, bunu bir ortaya çıkarma (raise)-if ifadesinde benzetmektir. Bu ifade test edilir ve sonuç yanlış ise bir istisna ortaya çıkar. Python onaylamalar için assert ifadesi ile gerçekleştirilir. Programcılar genellikle geçerli girişleri kontrol etmek için bir fonksiyon başlangıcında ve geçerli bir çıkışı kontrol etmek için bir fonksiyon çağrısından sonra onaylamaları yerleştirirler.
11.2.1. assert ifadesi
Python yorumlayıcısı, bir assert ifadesi ile karşılaştığında, Python umulan doğru olan ekteki ifadeyi değerlendirir. İfade yanlışsa, Python bir AssertionError istisnasını oluşturur. Sözdizimi:
assert İfade[, argümanlar]
Eğer onaylama başarısız olursa, Python ArgumentExpression’u AssertionError için argüman olarak kullanır. AssertionError istisnası, try-except ifadesi kullanılarak başka herhangi bir istisna gibi yakalanabilir ve işlenebilir, ancak yönetilmezse, program sonlanacak ve bir iz bırakacaktır. Basit bir örnek ile açalım. Aşağıdaki örnek, sıcaklığı Kelvin’den Fahrenhayt derecesine dönüştüren bir fonksiyondur. Sıfır derece Kelvin, en son derecede soğuk olduğu için, negatif bir sıcaklık görürse fonksiyon farklı çalışır.
1 2 3 4 5 6 7 |
def KelvinToFahrenheit(sicaklik): assert (sicaklik >= 0),"Mutlak sıfırdan daha soğuk!!!" return ((sicaklik-273)*1.8)+32 print(KelvinToFahrenheit(273)) print(int(KelvinToFahrenheit(505.78))) print(KelvinToFahrenheit(-5)) # assert ifadesi devreye girer. Onay şartı gerçekleşmez. |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
32.0 451 --------------------------------------------------------------------------- AssertionError Traceback (most recent call last) <ipython-input-6-abeeb9c010b2> in <module>() ----> 1 print(KelvinToFahrenheit(-5)) <ipython-input-3-a731148c832c> in KelvinToFahrenheit(sicaklik) 1 def KelvinToFahrenheit(sicaklik): ----> 2 assert (sicaklik >= 0),"Mutlak sıfırdan daha soğuk!!!" 3 return ((sicaklik-273)*1.8)+32 AssertionError: Mutlak sıfırdan daha soğuk!!! |
11.3. İstisna (Exception) nedir?
Bir istisna, programın talimatlarının normal akışını bozan bir programın yürütülmesi sırasında meydana gelen bir olaydır. Genel olarak, bir Python betiği onunla baş edemediği bir durumla karşılaştığında, bir istisna ortaya çıkarır. Bir istisna, bir hatayı temsil eden bir Python nesnesidir. Bir Python betiğinde bir istisna oluşturduğunda, istisnayı hemen ele almalıdır, aksi takdirde program sona erer ve sonlanır.
11.3.1. Bir istisnayı yönetme
Bir istisna oluşturabileceğini düşündüğünüz kod satırı var ise şüpheli kodu “try:” bloğuna yerleştirerek programınızın sonlanmasını engelleyebilirsiniz. “try:” bloğundan sonra, bir except: ifadesi eklenmeli ve sorun ile ilgili bilgi veren bir kod satırı yazabilirsiniz. Sözdizimi:
1 2 3 4 5 6 7 8 9 10 |
try: #İstisna oluşabilecek satır veya satırlar ...................... except ExceptionI: #Birinci tür hata olursa çalışan kod bloğu except ExceptionII: #İkincii tür hata olursa çalışan kod bloğu #......................#n istisna else: #Eğer hiç bir expection gerçekleşme ise çalışacak blok |
Yukarıda bahsedilen sözdizimi ile ilgili önemli noktalar:
- Bir try bloğunun birden fazla istisna bloğu olabilir. Çünkü bir try bloğu içinde birden farklı hata tetiklenebilir.
- Temel bir exception kullanarak birden fazla hatayı tek exception içine alabilirsiniz.
- Exception bloklarından sonra else ifadesi eklenebilir. Bu bölüm try bloğundan hata oluşma ise çalışır.
- Else bloğu hata oluşma kontrolüne ihtiyaç duymayan kodlar için uygun bir bloktur.
Şimdi bir tane hata içermeyen bir örnek bir tane de içeren bir örnek yapalım. Bunun için dosyaya yazma işlemi yapacağız.
1 2 3 4 5 6 7 8 |
try: fh = open("file01.txt", "w") fh.write("Bu bir istisna örneği, düzgün çalışması bekleniyor.") except IOError: print("Dosya bulunamadı veya okunamadı hatası") else: print("Yazılan içerik başarılı bir şekilde yazıldı") fh.close() |
1 |
Yazılan içerik başarılı bir şekilde yazıldı |
Şimdi okuma için açılmış bir dosyay yazma işlemi yapmaya çalışalım. Yazma satırında bir istisna beklenir ve bu yüzden bu blok try ifadesi içindedir. Örneğin,
1 2 3 4 5 6 7 8 |
try: fh = open("file01.txt", "r") fh.write("Okuma için açılan dosyaya yazma işlemi yapılıyor.") except IOError: print("Dosya bulunamadı veya bir işlem hatası") else: print("Yazılan içerik başarılı bir şekilde yazıldı") fh.close() |
1 |
Dosya bulunamadı veya bir işlem hatası |
11.3.2. Genel istisna
Yukarıdaki örnekte IOError istisna sınıfı kullanıldı. Aslında tüm istisnalar exception temel sınıfına bağlı olduğunu belirtmiştik. Eğer istisnanın tam türünü bilmiyorsanız sadece except ifadesini kullanıp hataları yakalayabilirsiniz. Sözdizimi:
1 2 3 4 5 6 7 8 |
try: #Hata oluşabilecek işlem/ler; #...................... except: #Eğer herhangi bir hata olursa bu blok çalışır. #...................... else: #Eğer hiçbir hata olmazsa bu blok çalışır. |
Bu tür bir try-except ifadesi, gerçekleşen tüm özel durumları yakalar. Bu tür bir try-except deyimini kullanmak, iyi bir programlama uygulaması olarak kabul edilmez. Çünkü böyle bir durum programcının hataya hakim olmadığını gösterir. Ayrıca ortaya çıkabilecek beklenmeyen hatalar kontrol edilemez bir şekilde yakalanmış olur.
11.3.3. Tüm istisnaları tek expect bloğunda toplama
Bütün hatalar aynı except bloğunda toplanabilir. Sözdizimi:
1 2 3 4 5 6 7 8 |
try: #Hata oluşturabilecek işlem/ler #...................... except(Exception1[, Exception2[,...ExceptionN]]]): #Eğer yukarıdaki hatalardan biri dahi oluşsa, bu bloğu çalıştır. #...................... else: #Eğer hiç bir hata oluşmazsa bu bloğu çalıştır. |
11.3.4. try-finally
try bloğu ile birlikte finally bloğu kullanabilirsiniz. finally bloğu, try bloğunda bir istisna oluşup oluşmadığına bakmadan yürütülmesi istenen herhangi bir kodun yerleştirileceği yerdir. Sözdizimi:
1 2 3 4 5 6 7 |
try: #İşlem/ler #...................... #Bir hata oluşsa da bu atlanabilir. finally: #Bu kod bloğu her zaman çalışır. #...................... |
finally bloğu else bloğu ile beraber kullanılmaz.
1 2 3 4 5 |
try: fh = open("testfile", "w") fh.write("Bu bir hata yakalama örneği!!") finally: print("Her durumda bu kod çalışır") |
1 |
Her durumda bu kod çalışır |
Şimdi hem finally hem de except bloğu içeren bir örnek yapalım.
1 2 3 4 5 6 7 8 9 |
try: fh = open("testfile", "w") try: fh.write("Bir hata yakalama örneği!!") finally: print("Dosya kapanıyor") fh.close() except IOError: print("Bir IO hatası oluştu!!!") |
1 |
Dosya kapanıyor |
try bloğunda bir istisna ortaya çıktığında, kod hemen finally bloğa geçer. Finally bloğundaki tüm ifadeler yürütüldükten sonra istisna tekrar ortaya çıkar. try-except ifadesinin bir sonraki üst katmanında bulunuyorsa istisna ifadelerinde ele alınır.
11.3.5. Bir istisnanın argümanı
Bir istisna, problem hakkında ek bilgi veren bir değer olan bir argümana sahip olabilir. Argümanın içeriği istisnaya göre değişir. Bir istisnanın argümanını aşağıdaki gibi bir istisna koşulunda bir değişken sağlayarak yakalarsınız. Sözdizimi:
1 2 3 4 5 |
try: #İşlemler #...................... except ExceptionType: #Buraya argümandan gelen değer yazdırılabilir... |
Tek bir özel istisna ile başa çıkmak için kod yazarsanız, bir değişkene sahipsinizdir. Birden çok özel durumu yakalarsanız, bir değişkenin istisnanın tuplesini takip edebilirsiniz. Bu değişken, genellikle istisnanın nedenini içeren istisnanın değerini alır. Değişken, tek bir değer veya bir tuple şeklinde birden çok değer alabilir. Bu tuple genellikle hata dizesini, hata numarasını ve bir hata konumunu içerir. Örneğin,
1 2 3 4 5 6 7 8 |
def temp_convert(var): try: return int(var) except ValueError: print("Argüman sayı içermiyor", ValueError) #Fonksiyonu çağırma temp_convert("xyz") |
1 |
Argüman sayı içermiyor <class 'ValueError'> |
11.3.5. İstisnaları ortaya çıkarma
raise ifadesini kullanarak çeşitli yollarla istisnalar oluşturabilirsiniz. raise ifadesi için genel sözdizimi:
raise [Exception [, args [, traceback]]]
Burada, Expection özel durum istisna türüdür. args istisna argümanı için bir değerdir. args seçimliktir; sağlanmadığı takdirde istisna argümanı yoktur. Son argüman, traceback de isteğe bağlıdır (nadiren kullanılır) ve eğer varsa, istisna için kullanılan traceback nesnesidir.
Bir istisna bir katar, bir sınıf veya bir nesne olabilir. Python çekirdeğinin var olan istisnaların çoğu sınıftır. Yeni istisnaları tanımlamak oldukça kolaydır. Örneğin,
1 2 3 4 5 |
def fonksiyonAdi( level ): if level < 1: raise("Geçerli seviye!", level) # Aşağıdaki kod çalıştırılamaz # Eğer istisna raise edilmezse |
Not: Bir istisna yakalamak için, bir “expect” ifadesi sınıf nesnesini veya basit bir katara atılan aynı özel duruma başvurmalıdır. Örneğin, yukarıdaki istisnayı yakalamak için aşağıdaki gibi bir istisna yazmalıyız.
1 2 3 4 5 6 |
try: #Kodlar... except "Geçersiz seviye!": #Exception burada yönetilir... else: #Expection olmadığı durumda çalışan satırlar... |
11.3.6. Kullanıcı-tanımlı istisnalar
Python, standart yerleşik istisnaları kullanarak kendi istisnalarınızı oluşturmanıza olanak sağlar. Örneğin,
1 2 3 |
class AgHatasi(RuntimeError): def __init__(self, arg): self.args = arg |
Yukarıda RuntimeError ile ilgili bir örnektir. Burada, RuntimeError’dan alt sınıflanmış bir sınıf oluşturulur. __init__ bir yapıcı ile bilgiler alınıyor. Bir yapıcıda, bir istisna yakalandığında daha spesifik bilgileri görüntülemeniz gerektiğinde kullanıcı-tanımlı istisnalar yararlı olur. Yukarıdaki hatayı oluşturmak için aşağıdaki satırlara benzer satırlara ihtiyaç vardır.
1 2 3 4 |
try: raise AgHatasi("Hatalı host adı") except AgHatasi as e: print(e.args) |
try bloğunda, kullanıcı tanımlı istisna ortaya çıkar ve istisna blokta yakalanır. Değişken e, Networkerror sınıfının bir örneğini oluşturmak için kullanılır.