Site Loader

Merhaba Arkadaşlar

Bugün sizlerle beraber Python Eğitim serisinin bu dersinde Python Hata Yakalama ve İstisnaları anlatacağım. Güzel bir ders olacak 🙂

Hata Yakalama

Şimdiye kadar yazdığımız bütün programlar, dikkat ettiyseniz tek bir ortak varsayım üzerine kurulu. Buna göre biz, yazdığımız programın kullanıcı tarafından nasıl kullanılmasını istiyorsak, her zaman o şekilde kullanılacağını varsayıyoruz. Örneğin sayıları toplayan bir program yazdığımızda, kullanıcının her zaman sayı değerli bir veri gireceğini düşünüyoruz. Ancak bütün iyi niyetimize rağmen, yazdığımız programlarda işler her zaman beklediğimiz gibi gitmeyebilir. Örneğin, dediğimiz gibi, yazdığımız programı, kullanıcının bir sayı girmesi temeli üzerine kurgulamışsak, kullanıcının her zaman sayı değerli bir veri gireceğinden emin olamayız.

birincisayı = int(input("Bir  sayı girinz : "))
toplam = birincisayı * 0.5

print(f"{birincisayı} sayısının 0.5 çarpımı  : {toplam} ")

ikincisayı = int(input("Karesini hesaplamak istediğiniz sayı: "))
kare = veri2 ** 2

print(f"{ikincisayı} sayısının karesi: {kare}")

Böyle bir kodumuz var kodu anlamadan önce şöyle bakalım çarpma ve karekök alıyor yani sayı girilmesi gerek o zaman bir çıktısına bakalım.
Çıktı:

Bir  sayı girinz : 5
5 sayısının 0.5 çarpımı  : 2.5 
Karesini hesaplamak istediğiniz sayı: 5
5 sayısının karesi: 25

Evet gördüğünüz gibi programımız çok güzel çalıştı hata yok gibi gözüküyor o zaman şöyle yapalım birde kullanıcı sayı girmesi gerektiği yerde string girse program ne gibi bir sonuç döndürecek bize
Örneğin kullanıcı yukarıdaki programa bir sayı yerine, (bilerek veya bilmeyerek) içinde harf barındıran bir veri girerse şuna benzer bir hata alır:
Hatalı Çıktı:

Bir  sayı girinz : k
Traceback (most recent call last):
  File "C:/Users/Onelife/PycharmProjects/pythonProject/venv/Include/Python_Earth_Ornek/hata _yakalama.py", line 1, in <module>
    birincisayı = int(input("Bir  sayı girinz : "))
ValueError: invalid literal for int() with base 10: 'k'

Yazdığınız programların bu tür hatalar vermesi normaldir. Ancak son kullanıcı açısından düşündüğümüzde, kullanıcının yukarıdaki gibi bir hata mesajı görmesi yerine, hatanın neden kaynaklandığını ya da neyi yanlış yaptığını daha açık bir şekilde ifade eden bir mesaj alması çok daha mantıklı olacaktır. Zira yukarıdaki hata mesajı programcılar açısından anlamlı olabilir, ancak son kullanıcı açısından büsbütün anlaşılmazdır!

Dediğimiz gibi, programınızın çalışma esnasında bu tür hatalar vermesi normal. Çünkü yapmaya çalıştığınız işlem, kullanıcının belli tipte bir veri girmesine bağlı. Burada sizin bir programcı olarak göreviniz, yazdığınız programın çalışma esnasında vermesi muhtemel hataları önceden kestirip, programınızda buna göre bazı önlemler almanızdır. İşte biz de bu bölümde bu önlemleri nasıl alacağımızı anlamaya çalışacağız.

Hata Türleri

Biz bu bölümde hatalardan bahsedeceğimizi söylemiştik. Ancak her şeyden önce ‘hata’ kavramının çok boyutlu olduğunu hatırlatmakta fayda var. Özellikle programcılık açısından hata kavramının ne anlama geldiğini biraz incelememiz gerekiyor.

Biz bu bölümde hataları üç farklı başlık altında ele alacağız:

  1. Programcı Hataları (Error)
  2. Program Kusurları (Bug)
  3. İstisnalar (Exception)

Öncelikle programcı hatalarından bahsedelim.

ad="Ahmet"
print(ad

Bu kodu çalıştırdığımızda şöyle bir hata verecek.
Çıktı:

  File "C:/Users/Onelife/PycharmProjects/pythonProject/venv/Include/Python_Earth_Ornek/asal.py", line 28
                ^
SyntaxError: unexpected EOF while parsing

Bu hata mesajında bizi ilgilendiren kısım son cümlede yer alıyor: SyntaxError, yani Söz dizimi hatası.

Bu hatalar, programlama diline ilişkin bir özelliğin yanlış kullanımından veya en basit şekilde programcının yaptığı yazım hatalarından kaynaklanır. Programcının hataları genellikle SyntaxError şeklinde ortaya çıkar. Bu hatalar çoğunlukla programcı tarafından farkedilir ve program kullanıcıya ulaşmadan önce programcı tarafından düzeltilir. Bu tür hataların tespiti diğer hatalara kıyasla kolaydır. Çünkü bu tür hatalar programınızın çalışmasını engellediği için bunları farketmemek pek mümkün değildir…

 Program kusurları, başka bir deyişle bug’lar ise çok daha karmaşıktır. Kusurlu programlar çoğu zaman herhangi bir hata vermeden çalışır. Ancak programın ürettiği çıktılar beklediğiniz gibi değildir. Örneğin yazdığınız programda bir formül hatası yapmış olabilirsiniz. Bu durumda programınız hiçbir şey yokmuş gibi çalışır, ancak formül hatalı olduğu için hesaplamaların sonuçları yanlıştır. Örneğin daha önceki derslerimizde yazdığımız şu program yukarıdaki gibi bir kusur içerir:

sayı1 = input("Toplama işlemi için ilk sayıyı girin: ")
sayı2 = input("Toplama işlemi için ikinci sayıyı girin: ")

print(sayı1, "+", sayı2, "=", sayı1 + sayı2)

Bu programda kullanıcı veri girdiği zaman, programımız toplama işlemi değil karakter dizisi birleştirme işlemi yapacaktır. Böyle bir program çalışma sırasında hata vermeyeceği için buradaki sorunu tespit etmek, özellikle büyük programlarda çok güçtür. Yani sizin düzgün çalıştığını zannettiğiniz program aslında gizliden gizliye bir bug barındırıyor olabilir.

Gelelim üçüncü kategori olan istisnalara (exceptions)…

ilksayı = input("ilk sayı giriniz: ")
ikincisayı = input("ikinci sayı giriniz: ")

ilksayı = int(ilksayı)
ikincisayı = int(ikincisayı)

print(ilksayı, "/", ikincisayı, "=", ilksayı / ikincisayı)

Burada ilk sayıyı ikinci sayıya bölen bir program yazdık. Bu program her türlü bölme işlemini yapabilir. Ama burada hesaba katmamız gereken iki şey var:

  1. Kullanıcı sayı yerine, sayı değerli olmayan bir veri tipi girebilir. Mesela ilk sayıya karşılık 23, ikinci sayıya karşılık ‘fdsfd’ gibi bir şey yazabilir.
  2. Kullanıcı bir sayıyı 0’a bölmeye çalışabilir. Mesela ilk sayıya karşılık 23, ikinci sayıya karşılık 0 yazabilir.

İlk durumda programımız şöyle bir hata verir:

ilksayı: 23
ikincisayı: fdsfd
Traceback (most recent call last):
  File "deneme.py", line 5, in <module>
    ikincisayı = int(ikincisayı)
ValueError: invalid literal for int() with base 10: 'fdsfd'

Buradaki sorun, sayı değerli olmayan bir verinin, int() fonksiyonu aracılığıyla sayıya çevrilmeye çalışılıyor olması.

İkinci durumda ise programımız şöyle bir hata verir:

ilksayı: 23
ikincisayı: 0
Traceback (most recent call last):
  File "deneme.py", line 7, in <module>
    print(ilksayı, "/", ikinci_sayı, "=", ilksayı / ikincisayı)
ZeroDivisionError: division by zero

Buradaki sorun ise, bir sayının 0’a bölünmeye çalışılıyor olması. Matematikte sayılar 0’a bölünemez.

İşte bu iki örnekte gördüğümüz ValueError ve ZeroDivisionError birer istisnadır. Yani kullanıcıların, kendilerinden sayı beklenirken sayı değerli olmayan veri girmesi veya bir sayıyı 0’a bölmeye çalışması istisnai birer durumdur ve yazdığımız programların exception (istisna) üretmesine yol açar

Konuyla ilgili temel bilgileri edindiğimize göre asıl meseleye geçebiliriz.

try-except

Bir önceki bölümde hatalardan ve hataları yakalamaktan söz ettik. Peki bu hataları nasıl yakalayacağız?

Python’da hata yakalama işlemleri için try-except bloklarından yararlanılır. Hemen bir örnek verelim:

while True:
    x = input("Bir sayı girin: ")
    if not x:
        break
    try:
        y = float(x)
    except ValueError:
        print("Geçersiz sayı")
        continue
    print(y**2)

Bu programda, hata mesajı çıkarabilecek bölümü try: blokunun içine aldık. Eğer float(x) işlemi valueError hatası verirse except ValueError bloku çalıştırılır, ve kullanıcıya bir uyarı verilerek tekrar döngünün başına dönülür. Bu sayede program durmadan hatayı yakalayıp sorunu gidermiş oluruz.
Yukarıda Türkçeye çevirdiğimiz emri Python kodunda nasıl ifade ettiğimize dikkat edin. Temel olarak şöyle bir yapıyla karşı karşıyayız:

try:
    hata verebileceğini bildiğimiz kodlar
except HataAdı:
    hata durumunda yapılacak işlem

Hatırlarsanız bir sayının 0’a bölünmesinin mümkün olmadığını, böyle bir durumda programımızın hata vereceğini söylemiştik. Bu durumu teyit etmek için etkileşimli kabukta şu kodu deneyebilirsiniz:

5/0

Çıktı:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero

Daha önce de söylediğimiz gibi, bu hata mesajında bizi ilgilendiren kısım ZeroDivisionError. Demek ki bir sayı 0’a bölündüğünde Python ZeroDivisionError veriyormuş. O halde şöyle bir kod yazabiliriz:

sayi=int(input("Bir sayı giriniz))
sayi1=int(input("Bir sayı giriniz))
try:
   toplam=sayi/sayi1
   print(toplam)
except ZeroDivisionError:
    print("Bir sayıyı 0'a bölemezsiniz!")

try- except-as

Bildiğiniz gibi, Python bir programın çalışması esnasında hata üretirken çıktıda hata türünün adıyla birlikte kısa bir hata açıklaması veriyor. Yani mesela şöyle bir çıktı üretiyor:

ValueError: invalid literal for int() with base 10: 'a'

Burada ‘ValueError’ hata türünün adı, ‘invalid literal for int() with base 10: ‘a’’ ise hatanın açıklamasıdır. Eğer istersek, yazdığımız programda bu hata açıklamasına erişebiliriz. Dikkatlice bakın:

sayi=int(input("Bir sayı giriniz))
sayi1=int(input("Bir sayı giriniz))
try: toplam=sayi/sayi1
      print(toplam)
except ZeroDivisionError as hata:
      print(hata)

Bu programı çalıştırıp sayı değerli olmayan bir veri girersek hata çıktısı şöyle olacaktır:

invalid literal for int() with base 10: 'a'

Gördüğünüz gibi, bu defa çıktıda hata türünün adı (ValueError) görünmüyor. Onun yerine sadece hata açıklaması var.

Hata durumu hiyerarşisi

Hata durumları bir nesne hiyerarşisi içinde tanımlanır. Bunların en geneli BaseException sınıfıdır; diğer daha özelleşmiş hata durumları bunlardan türetilir.

Hata durumları hiyerarşisinin bir bölümü şöyledir (tam bir listeyi Python belgelerinde bulabilirsiniz)

BaseException
 +-- SystemExit
 +-- KeyboardInterrupt
 +-- Exception
      +-- StopIteration
      +-- StopAsyncIteration
      +-- ArithmeticError
      |    +-- FloatingPointError
      |    +-- OverflowError
      |    +-- ZeroDivisionError
      +-- ImportError
      |    +-- ModuleNotFoundError
      +-- LookupError
      |    +-- IndexError
      |    +-- KeyError
      +-- OSError
      +-- ValueError

 

try-excep- else

Daha önce de dediğimiz gibi, Python’da hata yakalama işlemleri için çoğunlukla try... except... bloklarını bilmek yeterli olacaktır. İşlerimizin büyük kısmını sadece bu blokları kullanarak halledebiliriz. Ancak Python bize bu konuda, zaman zaman işimize yarayabilecek başka araçlar da sunmaktadır. İşte try... except... else... blokları da bu araçlardan biridir. Bu bölümde kısaca bu blokların ne işe yaradığından söz edeceğiz.

Öncelikle try... except... else... bloğunun ne işe yaradığına bakalım. Esasında biz bu else deyimini daha önce de ‘koşullu ifadeler’ konusunu işlerken görmüştük. Buradaki kullanımı da zaten hemen hemen aynıdır. Diyelim ki elimizde şöyle bir şey var:

try:
    bölünen = int(input("bölünecek sayı: "))
    bölen = int(input("bölen sayı: "))
    print(bölünen/bölen)
except ValueError:
    print("hata!")

Burada eğer kullanıcı sayı yerine harf girerse ValueError hatası alırız. Bu hatayı except ValueError: ifadesiyle yakalıyoruz ve hata verildiğinde kullanıcıya bir mesaj göstererek programımızın çökmesini engelliyoruz. Ama biliyoruz ki, bu kodları çalıştırdığımızda Python’ın verebileceği tek hata ValueError değildir. Eğer kullanıcı bir sayıyı 0’a bölmeye çalışırsa Python ZeroDivisionError adlı hatayı verecektir. Dolayısıyla bu hatayı da yakalamak için şöyle bir şey yazabiliriz:

try:
    bölünen = int(input("bölünecek sayı: "))
    bölen = int(input("bölen sayı: "))
except ValueError:
    print("Lütfen sadece sayı girin!")
else:
    try:
        print(bölünen/bölen)
    except ZeroDivisionError:
        print("Bir sayıyı 0'a bölemezsiniz!")

Burada yaptığımız şey şu: İlk try... except... bloğu yardımıyla öncelikle int(input()) fonksiyonu ile kullanıcıdan gelecek verinin sayı olup olmadığını denetliyoruz. Ardından bir else... bloğu açarak, bunun içinde ikinci try... except... bloğumuzu devreye sokuyoruz. Burada da bölme işlemini gerçekleştiriyoruz. Kullanıcının bölme işlemi sırasında 0 sayısını girmesi ihtimaline karşı da except ZeroDivisionError ifadesi yardımıyla olası hatayı göğüslüyoruz.

Mesela yukarıda ilk try... bloğu içindeki dönüştürme işlemi yalnızca ValueError hatası verebilir. else: bloğundan sonraki try... bloğunda yer alan işlem ise ancak ZeroDivisionError verecektir. Biz yukarıda kullandığımız yapı sayesinde her bir hatayı tek tek ve yeri geldiğinde karşılıyoruz. Bu durumun aksine, bölümün ilk başında verdiğimiz try... except bloğunda hem ValueError hem de ZeroDivisionError hatalarının gerçekleşme ihtimali bulunuyor. Dolayısıyla biz orada bütün hataları tek bir try... bloğu içine sıkıştırmış oluyoruz. İşte else: bloğu bu sıkışıklığı gidermiş oluyor.

try-except-finally

try... except... else... yapılarının dışında, Python’ın bize sunduğu bir başka yapı da try... except... finally... yapılarıdır. Bunu şöyle kullanıyoruz:

try:
    ...bir takım işler...
except birHata:
    ...hata alınınca yapılacak işlemler...
finally:
    ...hata olsa da olmasa da yapılması gerekenler...

finally.. bloğunun en önemli özelliği, programın çalışması sırasında herhangi bir hata gerçekleşse de gerçekleşmese de işletilecek olmasıdır. Eğer yazdığınız programda mutlaka ama mutlaka işletilmesi gereken bir kısım varsa, o kısmı finally... bloğu içine yazabilirsiniz.

Fonksiyonlarımızda hata durumu yayınlamak

Gördüğümüz gibi birçok Python fonksiyonu normal işleyişe uymayan durumlarda bir hata durumu yayınlıyor, ve programımızda bu hata durumunu yakalayarak işlem yapıyoruz. Kendi yazdığımız fonksiyonların içinde raise komutu kullanarak bir hata durumu yayınlanmasını sağlayabiliriz. Örnek olarak, negatif argüman aldığında ValueError yayınlayan bir faktöriyel fonksiyonu yazalım. Hata mesajını değiştirmemiz de mümkündür:

def faktöryel(x):
    x = int(x)    
    if x<0:
        raise ValueError("Negatif değer")
    p = 1
    for i in range(1,x+1):
        p *= i
    return p

Şimdi bu fonksiyonu bir try/except bloku içinde kullanalım.

for x in [5, -5, "abc", 5]:
    try:
        y = faktöryel(x)
    except ValueError as e:
        print(x,": ", e)
        continue
    print(y)
120
-5 :  Negatif değer
abc :  invalid literal for int() with base 10: 'abc'
120

Yeni hata durumları yaratmak

Python’un standart hata durumlarına ek olarak, kendi hata durumlarımızı da yaratabiliriz. Yukarıda gördüğümüz hata durumu hiyerarşisi, aslında bir nesne hiyerarşisidir. Nesne sınıfları tanımlamayı sonraki bölümlerde göreceğiz, ama buradaki örneği nesne programlama bilmeden de uygulayabilirsiniz.

Yeni bir hata tanımlarken varolan bir hatayı temel alırız. Söz gelişi, genel Exception nesne sınıfından türetilmiş bir VektörBoyuHatası tanımlayalım.

class VektörBoyuHatası(Exception):
    pass

Buradaki pass kelimesi etkisiz bir komuttur. Python sözdizimi gereğince doldurulması gereken bir yere herhangi bir kod koymak istemediğimizde kullanırız.

Şimdi iki sayı listesinin iç çarpımını veren bir fonksiyon yazalım. Listeler aynı uzunlukta değilse iç çarpım tanımlı olmaz; bu durumda VektörBoyuHatası yayınlayalım.

def iç_çarpım(L1, L2):
    if len(L1)!=len(L2):
        raise VektörBoyuHatası("Parametreler aynı sayıda elemandan oluşmalı.")
    return sum( [a*b for (a,b) in zip(L1,L2)] )

Çıktı:

iç_çarpım([1,2,3], [-1,0,1])

Çıktı:

iç_çarpım([1,2,3,4], [-1,0,1])

Hata Çıktısı:

VektörBoyuHatası                          Traceback (most recent call last)
<ipython-input-9-5f70170b4bfa> in <module>()
----> 1 iç_çarpım([1,2,3,4], [-1,0,1])

<ipython-input-7-ec326e885a8f> in iç_çarpım(L1, L2)
      1 def iç_çarpım(L1, L2):
      2     if len(L1)!=len(L2):
----> 3         raise VektörBoyuHatası("Parametreler aynı sayıda elemandan oluşmalı.")
      4     return sum( [a*b for (a,b) in zip(L1,L2)] )

VektörBoyuHatası: Parametreler aynı sayıda elemandan oluşmalı.

Bu fonksiyonu bir try/except yapısı içinde kullanabiliriz:

try:
    iç_çarpım([1,2,3,4], [-1,0,1])
except VektörBoyuHatası as e:
    print(e)

Hatalı çıktı

Parametreler aynı sayıda elemandan oluşmalı.

Gördüğünüz gibi buda böyle çalışıyor.

Evet arkadaşlar pythonearth.com  Eğitim serisinin bu dersinde sizlere Python Hata Yakalama ve İstisnalar(try-except) anlattık. Umarım anlaşılır bir şekilde yazmışımdır eksik veya hatalı gördüğünüz noktaları belirtebilirsiniz mail veya yorumlar kısmından. Yazılarda zor anlaşılıyor ise Cahit hocamızın Youtube üzerinden yaptığı kısa kısa videolardan takip edebilirsiniz. Kanalın linkini bırakıyorum isteyenler buradan ulaşabilir.

 

Sağlıcakla kalın 🙂

 

Post Author: Sadık Ortaoglan

computer enginering

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir