Takip et

Python Temelleri: 9. Gün – Dosya İşlemleri ve Hata Yönetimi

Python öğrenme serimizin dokuzuncu gününe hoş geldiniz! Bu makalede, Python’ın en temel ama aynı zamanda en güçlü özelliklerinden ikisini, yani dosya işlemlerini ve hata yönetimini derinlemesine inceleyeceğiz. Kendi programlarınızı daha sağlam, güvenilir ve kullanıcı dostu hale getirmek için bu konuları öğrenmek, kariyerinizde size büyük avantajlar sağlayacaktır.

Herhangi bir yazılım geliştirme sürecinde, verilerle çalışmak kaçınılmaz bir gerekliliktir. Uygulamalarınızın sadece bellekte değil, kalıcı olarak da bilgi depolaması ve bu bilgilere erişebilmesi gerekir. İşte bu noktada dosya işlemleri devreye girer. Örneğin, bir web uygulamasının kullanıcı tercihlerini kaydetmesi, bir veri analizi aracının büyük veri setlerini okuması veya bir oyunun kaydettiği ilerlemeyi saklaması için dosya işlemleri hayati önem taşır. Dosyalar, programlarınızın disk üzerinde metin, resim, ses veya herhangi bir ikili veri formatında bilgi saklamasına olanak tanır. Böylece programınız kapatılsa bile verileriniz kaybolmaz ve daha sonra tekrar kullanılabilir.

Diğer yandan, bir program çalışırken beklenmedik durumlarla karşılaşması oldukça yaygındır. Kullanıcı yanlış bir girdi verebilir, bir dosya bulunamayabilir, ağ bağlantısı kesilebilir veya bir hesaplama hatası oluşabilir. Bu tür durumlarda programın aniden çökmesi, hem kötü bir kullanıcı deneyimine yol açar hem de veri kaybına neden olabilir. İşte burada hata yönetimi, yani exception handling, kurtarıcı rol oynar. Hata yönetimi, programınızın bu tür beklenmedik olayları zarif bir şekilde ele almasını, hataları yakalamasını ve programın çökmesini engellemesini sağlar. Bu sayede uygulamanız daha sağlam, dayanıklı ve güvenilir hale gelir. Özellikle veri girişi gibi dış kaynaklarla etkileşime giren her durumda hata yönetimi bir zorunluluktur. Bir Python programcısı olarak, bu iki konuya hakim olmak, sadece kod yazma becerinizi değil, aynı zamanda ürettiğiniz yazılımın kalitesini de doğrudan etkiler. Bu bağlamda, bu iki temel konuyu öğrenmek, Python yolculuğunuzda önemli bir mihenk taşıdır.

Öncelikle, dosya işlemleri, veri kalıcılığı sağlamanın en temel yollarından biridir. Düşünün ki, her gün kullandığınız bir not defteri uygulaması, yazdığınız notları kaydetmese ne kadar işe yarardı? Ya da bir finans uygulaması, tüm geçmiş işlemlerinizi her kapandığında unutsaydı? İşte bu durumları engellemek için dosyalar kullanılır. Python, metin dosyalarından ikili (binary) dosyalara kadar birçok farklı dosya türüyle çalışmak için basit ve etkili yöntemler sunar. Veri analizi projelerinde CSV veya JSON dosyalarından veri okumak, web sunucularının loglarını incelemek veya kendi özel veri formatlarınızı oluşturmak gibi pek çok senaryoda dosya okuma ve yazma bilgisine ihtiyacınız olacaktır.

Dahası, hata yönetimi, kullanıcı deneyimini doğrudan etkileyen bir faktördür. Hiçbir kullanıcı, kullandığı bir uygulamanın aniden kapanmasını veya anlamsız bir hata mesajı vermesini istemez. İyi bir hata yönetimi stratejisi, kullanıcılara ne olduğunu açıklayan, durumu düzeltmeleri için yönlendiren veya en azından programın zarif bir şekilde kapanmasını sağlayan bir mekanizma sunar. Bu, programınızın profesyonelliğini ve güvenilirliğini gösterir. Python’ın sunduğu try-except blokları, bu tür durumları kontrol altına almanın en yaygın ve etkili yoludur. Dolayısıyla, hem veri kalıcılığı hem de kullanıcı deneyimi açısından dosya işlemleri ve hata yönetimi, modern Python programcılığının olmazsa olmazlarındandır.

Python ile Dosya Okuma ve Yazma İşlemleri Nasıl Yapılır?

Python’da dosya işlemleri, open() fonksiyonu ile başlar. Bu fonksiyon, bir dosyayı belirtilen modda açar ve bir dosya nesnesi döndürür. Bu dosya nesnesi üzerinden dosyaya okuma, yazma veya ekleme gibi işlemler yapabiliriz. Ancak, dosya işlemleri bittiğinde dosyayı kapatmayı unutmamak çok önemlidir. Aksi takdirde, veri kaybı veya dosya bozulmaları gibi sorunlarla karşılaşabiliriz. Neyse ki Python, bu süreci güvenli hale getiren with ifadesini sunar.

open() Fonksiyonu ve Dosya Modları

open() fonksiyonu iki ana argüman alır: dosya yolu (string) ve mod (string). Mod, dosyayı hangi amaçla açtığımızı belirtir. İşte en sık kullanılan dosya modları:

Mod Açıklama Örnek Kullanım
‘r’ Okuma modu (varsayılan). Dosya bulunamazsa FileNotFoundError hatası verir. f = open('dosya.txt', 'r')
‘w’ Yazma modu. Dosya varsa içeriğini siler, yoksa yeni bir dosya oluşturur. f = open('dosya.txt', 'w')
‘a’ Ekleme (append) modu. Dosya varsa sonuna ekler, yoksa yeni bir dosya oluşturur. f = open('dosya.txt', 'a')
‘x’ Özel yazma modu. Dosya varsa FileExistsError hatası verir, yoksa yeni bir dosya oluşturur. f = open('dosya.txt', 'x')
‘b’ İkili (binary) mod. Genellikle ‘rb’, ‘wb’, ‘ab’ şeklinde diğer modlarla birlikte kullanılır. f = open('resim.jpg', 'rb')
‘t’ Metin modu (varsayılan). ‘rt’, ‘wt’ gibi diğer modlarla birlikte kullanılır. f = open('metin.txt', 'rt')

Dosya Okuma Yöntemleri

Bir dosya nesnesi elde ettikten sonra, içeriğini okumak için çeşitli yöntemler kullanabiliriz:

  • read(): Dosyanın tüm içeriğini tek bir string olarak okur. İsteğe bağlı olarak argüman olarak bir tam sayı (byte/karakter sayısı) alabilir.
  • readline(): Dosyanın sadece bir satırını okur. Satır sonunda yeni satır karakterini (\n) içerir.
  • readlines(): Dosyanın tüm satırlarını bir liste halinde okur. Her liste öğesi bir satırı temsil eder ve sonlarında \n karakterini içerir.

# Ornek bir dosya olusturalim
with open('deneme.txt', 'w') as f:
    f.write('Merhaba, Python!\n')
    f.write('Bu dosya islemleri icin bir ornektir.\n')
    f.write('Ucuncu satiri da ekleyelim.\n')

# Dosyayi okuma ornekleri
print("--- read() ile tum dosyayi okuma ---")
with open('deneme.txt', 'r') as f:
    icerik = f.read()
    print(icerik)

print("\n--- readline() ile satir satir okuma ---")
with open('deneme.txt', 'r') as f:
    print(f.readline(), end='') # ilk satır
    print(f.readline(), end='') # ikinci satır

print("\n--- readlines() ile tum satirlari liste olarak okuma ---")
with open('deneme.txt', 'r') as f:
    satirlar = f.readlines()
    for satir in satirlar:
        print(satir.strip()) # .strip() ile \n karakterlerini temizleyelim

print("\n--- Dosyayi dongu ile satir satir okuma (en yaygin ve hafiza dostu yontem) ---")
with open('deneme.txt', 'r') as f:
    for satir in f:
        print(satir.strip())

Dosyaya Yazma Yöntemleri

Dosyaya yazmak için write() ve writelines() yöntemlerini kullanırız:

  • write(string): Verilen stringi dosyaya yazar. Yeni satır karakterini kendiniz eklemelisiniz (\n).
  • writelines(list_of_strings): Bir string listesindeki her öğeyi dosyaya yazar. Listedeki her öğe için ayrı ayrı yeni satır karakteri eklemeniz gerekebilir.

# Dosyaya yazma ornegi ('w' modu icerigi siler)
print("--- Dosyaya yazma (overwrite) ---")
with open('yeni_dosya.txt', 'w') as f:
    f.write('Bu, yeni olusturulan bir dosyadir.\n')
    f.write('Ikinci satir.\n')

# Dosyaya ekleme ornegi ('a' modu)
print("\n--- Dosyaya ekleme ---")
with open('yeni_dosya.txt', 'a') as f:
    f.write('Bu da eklenen bir satirdir.\n')
    f.write('Son eklenen satir.\n')

# Kontrol edelim
with open('yeni_dosya.txt', 'r') as f:
    print(f.read())

Uzman İpucu: Dosya yolları konusunda platformlar arası uyumluluk sağlamak için os.path veya daha modern pathlib modülünü kullanın. Örneğin, os.path.join('klasor', 'dosya.txt') farklı işletim sistemlerinde doğru yolu üretecektir. Bu, özellikle büyük ve çok platformlu projelerde hata riskini azaltır.

Gerçek Dünya Senaryosu: Log Dosyalarını İşlemek

Şimdi gerçekçi bir senaryoya bakalım: Bir web sunucusunun veya uygulamanın log dosyalarını işlemek. Log dosyaları, sistemde meydana gelen olayları, hataları, kullanıcı erişimlerini kaydeder. Bu dosyalardan belirli bilgileri (örneğin, belirli bir hata mesajını veya bir IP adresinden gelen istekleri) ayıklamak sıkça karşılaşılan bir görevdir.


# log.txt adinda ornek bir log dosyasi olusturalim
log_icerigi = """
2023-10-26 10:00:05 [INFO] Kullanici 'ali' sisteme giris yapti.
2023-10-26 10:01:10 [WARNING] Disk alani dusuk: %80 dolu.
2023-10-26 10:02:30 [ERROR] Veritabani baglantisi hatasi: Connection refused.
2023-10-26 10:03:15 [INFO] Kullanici 'veli' ana sayfayi ziyaret etti.
2023-10-26 10:04:00 [ERROR] Dosya bulunamadi: 'ayarlar.conf'.
2023-10-26 10:05:01 [INFO] Yeni kullanici 'ayse' kayit oldu.
"""
with open('log.txt', 'w') as f:
    f.write(log_icerigi.strip())

# Log dosyasindan sadece ERROR seviyesindeki mesajlari ayiklayalim
hata_mesajlari = []
try:
    with open('log.txt', 'r') as log_file:
        for satir in log_file:
            if '[ERROR]' in satir:
                hata_mesajlari.append(satir.strip())
    
    if hata_mesajlari:
        print("Log dosyasinda bulunan hata mesajlari:")
        for hata in hata_mesajlari:
            print(hata)
    else:
        print("Log dosyasinda hata mesajina rastlanmadi.")

except FileNotFoundError:
    print("Hata: 'log.txt' dosyasi bulunamadi.")
except Exception as e:
    print(f"Beklenmeyen bir hata olustu: {e}")

# Ayikladigimiz hata mesajlarini ayri bir dosyaya kaydedelim
if hata_mesajlari:
    with open('hatalar.log', 'w') as error_file:
        for hata in hata_mesajlari:
            error_file.write(hata + '\n')
    print("\nHata mesajlari 'hatalar.log' dosyasina kaydedildi.")

Bu örnekte, bir log dosyasından belirli anahtar kelimeleri ([ERROR]) içeren satırları filtreleyip başka bir dosyaya kaydettik. Bu, veri işleme, raporlama ve hata ayıklama süreçlerinde sıklıkla kullanılan temel bir dosya işlemi senaryosudur. Gördüğünüz gibi, with open(...) yapısı sayesinde dosyaları açma ve kapatma işlemleri otomatik olarak yönetilir, bu da kaynak sızıntılarını önler.

Python'da Hata Yönetimi: Programlarınızı Sağlamlaştırmanın Yolu

Her programcı bilir ki, hatalar kod yazım sürecinin ayrılmaz bir parçasıdır. Ancak önemli olan, bu hataların programınızın çökmesine neden olmadan, zarifçe nasıl yönetildiğidir. Python, bu konuda oldukça güçlü ve esnek bir yapı sunar: try-except-else-finally blokları. Bu yapılar sayesinde, potansiyel olarak hata oluşturabilecek kod parçalarını izole edebilir ve programınızın kesintiye uğramadan çalışmaya devam etmesini sağlayabilirsiniz.

try, except, else ve finally Blokları

Hata yönetiminin temelini oluşturan bu blokları adım adım inceleyelim:

  • try: Bu blok, hata oluşturma potansiyeli olan kodu içerir. Python bu bloktaki kodu yürütürken bir hata ile karşılaşırsa, except bloğuna atlar. Eğer hata oluşmazsa, except bloğu atlanır.
  • except: try bloğunda belirli bir hata (veya tüm hatalar) yakalandığında çalışacak kod bu blokta yer alır. Hata türünü belirterek sadece o tür hataları yakalayabiliriz. Örneğin, except ValueError: sadece ValueError hatalarını yakalar. Genel bir except: bloğu tüm hataları yakalar, ancak bu genellikle iyi bir uygulama değildir.
  • else: Eğer try bloğunda hiçbir hata oluşmazsa, except bloğundan sonra else bloğu çalışır. Bu genellikle, try bloğundaki işlem başarıyla tamamlandığında yapılacak işlemleri kapsar.
  • finally: Bu blok, try-except bloğu içinde hata oluşsa da oluşmasa da her zaman çalıştırılır. Genellikle kaynakları (açık dosyalar, veritabanı bağlantıları vb.) temizlemek veya serbest bırakmak için kullanılır.

print("--- Basit Hata Yönetimi Örneği ---")
try:
    sayi1 = int(input("Birinci sayıyı girin: "))
    sayi2 = int(input("Ikinci sayıyı girin: "))
    sonuc = sayi1 / sayi2
except ValueError:
    print("Hata: Lütfen geçerli bir tam sayı girin.")
except ZeroDivisionError:
    print("Hata: Bir sayı sıfıra bölünemez.")
except Exception as e: # Genel hata yakalama, belirli hatalardan sonra kullanılmalı
    print(f"Beklenmeyen bir hata oluştu: {e}")
else:
    print(f"Bölme işlemi başarılı: {sayi1} / {sayi2} = {sonuc}")
finally:
    print("İşlem tamamlandı. Program devam ediyor.")

print("\n--- Dosya İşlemlerinde Hata Yönetimi ---")
dosya_adi = "mevcut_olmayan_dosya.txt"
try:
    with open(dosya_adi, 'r') as f:
        icerik = f.read()
        print(f"Dosya içeriği:\n{icerik}")
except FileNotFoundError:
    print(f"Hata: '{dosya_adi}' dosyası bulunamadı. Lütfen dosya adını kontrol edin.")
except IOError as e: # Dosya okuma/yazma sirasinda olusan diger hatalar
    print(f"Hata: Dosya islemi sirasinda bir problem olustu: {e}")
finally:
    print("Dosya işlem denemesi tamamlandı.")

Bu örneklerde, kullanıcı girişlerindeki tip dönüşüm hatalarını (ValueError) ve sıfıra bölme hatalarını (ZeroDivisionError) yakaladık. Ayrıca, dosya işlemleri sırasında oluşabilecek FileNotFoundError hatalarını da ele aldık. Gördüğünüz gibi, her bir hata türü için farklı bir mesaj vererek kullanıcıya daha açıklayıcı geri bildirimler sağlayabiliriz. Bu durum, Python programlama becerilerini pekiştirmek isteyenler için kritik bir konudur.

Vaka Analizi: Kullanıcı Girişini Güvenle Doğrulamak

Kullanıcıdan sayısal bir giriş bekleyen bir program yazdığınızı varsayalım. Ancak kullanıcı yanlışlıkla bir metin girebilir. Bu durumda programın çökmesini engellemek ve kullanıcıdan tekrar giriş yapmasını istemek için hata yönetimini kullanabiliriz.


def guvenli_sayi_al(mesaj):
    while True:
        try:
            giris = input(mesaj)
            sayi = int(giris)
            return sayi
        except ValueError:
            print("Geçersiz giriş! Lütfen sadece sayı girin.")
        except KeyboardInterrupt: # Kullanici Ctrl+C ile cikmak isterse
            print("\nProgram kullanıcı tarafından sonlandırıldı.")
            exit() # Programdan cık
        except Exception as e:
            print(f"Beklenmeyen bir hata oluştu: {e}")

yas = guvenli_sayi_al("Lütfen yaşınızı girin: ")
print(f"Yaşınız: {yas}")

fiyat = guvenli_sayi_al("Lütfen ürünün fiyatını girin: ")
print(f"Ürünün fiyatı: {fiyat} TL")

Bu guvenli_sayi_al fonksiyonu, kullanıcıdan geçerli bir tamsayı girişi alana kadar sürekli sorgular. Eğer ValueError hatası oluşursa (kullanıcı sayı yerine metin girerse), bir hata mesajı yazdırılır ve döngü tekrar eder. KeyboardInterrupt gibi daha genel hataları da yakalayarak programın kontrolsüz kapanmasını engellemek mümkündür. Bu tür bir yaklaşım, kullanıcı etkileşimli uygulamaların sağlamlığını önemli ölçüde artırır. Bu, temel Python bilgisinin bir uygulaması olarak programınızın stabilitesini artırır.

Python Modülleri ile Kodunuzu Daha Düzenli Hale Getirin

Bir program büyüdükçe, tüm kodu tek bir dosyada tutmak karmaşık ve yönetilemez hale gelebilir. İşte bu noktada Python modülleri ve paketleri devreye girer. Modüller, Python kodunuzu mantıksal olarak bölümlere ayırmanın ve yeniden kullanılabilir parçalar halinde organize etmenin harika bir yoludur. Kısacası, bir Python dosyası (.py uzantılı) bir modüldür ve bu modülün içindeki fonksiyonları, sınıfları ve değişkenleri başka bir Python dosyasında kullanabilirsiniz.

Modülleri İçe Aktarma (import)

Bir modülü kullanabilmek için onu projenize içe aktarmanız gerekir. Bunun için import ifadesini kullanırız.


# math_islemleri.py adinda bir dosya olusturalim
# Icine asagidaki kodu yazin ve kaydedin.
#
# def topla(a, b):
#     return a + b
#
# def cikar(a, b):
#     return a - b
#
# def carp(a, b):
#     return a * b
#
# PI_SAYISI = 3.14159

# Ana program dosyanizda (ornegin main.py)
import math_islemleri

sonuc_topla = math_islemleri.topla(10, 5)
print(f"Toplama sonucu: {sonuc_topla}")

sonuc_carp = math_islemleri.carp(7, 3)
print(f"Carpma sonucu: {sonuc_carp}")

print(f"PI sayisi: {math_islemleri.PI_SAYISI}")

# Belirli fonksiyonlari veya degiskenleri iceri aktarma
from math_islemleri import cikar, PI_SAYISI as PI

sonuc_cikar = cikar(20, 8)
print(f"Cikarma sonucu: {sonuc_cikar}")
print(f"PI degeri (farkli isimle): {PI}")

# Tumunu iceri aktarma (genellikle onerilmez, isim cakismalarina yol acabilir)
from math_islemleri import * 
# Artik topla(), cikar(), carp() ve PI_SAYISI direkt olarak kullanilabilir

Yukarıdaki örnekte, math_islemleri.py adında bir modül oluşturduk ve ardından bu modüldeki fonksiyonları ve değişkenleri import ifadesiyle ana programımıza dahil ettik. from ... import ... yapısı, modülün belirli bir kısmını doğrudan adıyla kullanmamızı sağlar. Bu, kodunuzu daha modüler ve okunabilir hale getirmenin temel bir adımıdır.

Paket Yapısı (Basitçe)

Modüllerin bir adım ötesi ise paketlerdir. Paketler, ilgili modülleri tek bir dizin altında gruplamanın bir yoludur. Bir dizinin bir Python paketi olarak kabul edilmesi için, o dizinin içinde özel bir dosya olan __init__.py bulunması gerekir (Python 3.3 ve sonrası için zorunlu olmasa da, iyi bir uygulama olarak hala kullanılır).


proje_klasoru/
├── main.py
└── hesaplama_paketi/
    ├── __init__.py
    ├── temel_islemler.py
    └── ileri_islemler.py

Burada hesaplama_paketi bir pakettir. temel_islemler.py ve ileri_islemler.py ise bu paketin içindeki modüllerdir. main.py dosyasından bu modüllere erişmek için aşağıdaki gibi bir yol izleyebiliriz:


# temel_islemler.py dosyasinin icerigi
# def topla(a, b):
#     return a + b

# ileri_islemler.py dosyasinin icerigi
# def us_al(taban, us):
#     return taban ** us

# main.py dosyasinin icerigi
from hesaplama_paketi import temel_islemler
from hesaplama_paketi.ileri_islemler import us_al

print(f"Toplama: {temel_islemler.topla(5, 3)}")
print(f"Üs alma: {us_al(2, 4)}")

Paketler, büyük projelerde kodu düzenlemenin ve isimlendirme çakışmalarını önlemenin olmazsa olmazıdır. Python'ın bu modüler yapısı, kodun yeniden kullanılabilirliğini artırır ve ekip içinde çalışmayı kolaylaştırır. Bir Python programı geliştirirken bu prensiplere uymak, sürdürülebilir bir kod tabanı oluşturmanın anahtarıdır.

Vaka Analizi: Bir Proje için Fonksiyonları Modüllere Ayırma

Bir veri analizi projesi üzerinde çalıştığınızı düşünelim. Bu projenin farklı aşamaları için farklı fonksiyonlara ihtiyacınız var: veri okuma, veri temizleme, veri analizi ve raporlama. Tüm bu fonksiyonları tek bir dosyada tutmak yerine, her aşama için ayrı bir modül oluşturmak projenizi daha yönetilebilir kılar.


# veri_okuyucu.py
def csv_oku(dosya_yolu):
    import csv
    with open(dosya_yolu, 'r', encoding='utf-8') as f:
        okuyucu = csv.reader(f)
        header = next(okuyucu) # Basligi oku
        veriler = [row for row in okuyucu]
    return header, veriler

# veri_temizleyici.py
def bosluklari_kaldir(liste_veri):
    temizlenmis_veri = []
    for satir in liste_veri:
        temizlenmis_satir = [eleman.strip() for eleman in satir]
        temizlenmis_veri.append(temizlenmis_satir)
    return temizlenmis_veri

# main_analiz.py
from veri_okuyucu import csv_oku
from veri_temizleyici import bosluklari_kaldir

# Ornek bir CSV dosyasi olusturalim
ornek_csv_icerik = """
isim,yas,sehir
Ali ,30 ,Ankara
Veli,25,Istanbul 
Ayşe,35, İzmir
"""
with open('ornek_veri.csv', 'w', encoding='utf-8') as f:
    f.write(ornek_csv_icerik.strip())

# Verileri oku
baslik, ham_veriler = csv_oku('ornek_veri.csv')
print("Ham Veriler:")
print(f"Başlık: {baslik}")
for satir in ham_veriler:
    print(satir)

# Verileri temizle
temiz_veriler = bosluklari_kaldir(ham_veriler)
print("\nTemizlenmiş Veriler:")
print(f"Başlık: {baslik}")
for satir in temiz_veriler:
    print(satir)

# Daha sonra temizlenmis verilerle analiz yapabiliriz
# ...

Bu örnekte, veri okuma ve veri temizleme işlemlerini ayrı modüllere ayırarak kodumuzu organize ettik. Bu sayede, main_analiz.py dosyamız daha temiz ve odaklı kalırken, her bir modül kendi özel işlevini yerine getiriyor. Bu yapı, hem okunabilirliği hem de bakım kolaylığını artırır. Python'da gelişmiş programlama yaparken bu tür modüler yaklaşımlar vazgeçilmezdir.

İleri Düzey İpuçları ve En İyi Uygulamalar

Temel dosya işlemleri ve hata yönetimine hakim olduktan sonra, uygulamalarınızı daha da optimize etmek ve daha sağlam hale getirmek için bazı ileri düzey ipuçları ve en iyi uygulamaları öğrenmek faydalı olacaktır. Bu, Python bilgisi edinirken programlama yeteneklerinizi bir üst seviyeye taşıyacaktır.

pathlib Modülü ile Dosya Yollarını Yönetmek

Geleneksel olarak dosya yolları os.path modülü ile yönetilse de, Python 3.4 ile gelen pathlib modülü, nesne yönelimli bir yaklaşımla dosya sistemi yollarını yönetmeyi çok daha kolay ve Pythonic hale getirir. Hem dosya yollarını birleştirme hem de dosya sistemi ile etkileşim kurma konusunda büyük kolaylıklar sunar.


from pathlib import Path

# Mevcut çalışma dizini
current_dir = Path.cwd()
print(f"Mevcut Dizin: {current_dir}")

# Yeni bir dosya yolu oluşturma
dosya_yolu = current_dir / 'data' / 'rapor.txt'
print(f"Oluşturulan Yol: {dosya_yolu}")

# Klasör ve dosya varlığını kontrol etme
if not dosya_yolu.parent.exists():
    dosya_yolu.parent.mkdir() # data klasörünü oluştur

# Dosya oluşturma ve yazma
if not dosya_yolu.exists():
    dosya_yolu.write_text("Bu bir test raporudur.\nİkinci satır.")
    print(f"'{dosya_yolu}' dosyası oluşturuldu ve yazıldı.")

# Dosya içeriğini okuma
if dosya_yolu.exists():
    icerik = dosya_yolu.read_text()
    print(f"\n'{dosya_yolu}' içeriği:\n{icerik}")

# Dosya adını veya uzantısını alma
print(f"Dosya adı: {dosya_yolu.name}")
print(f"Dosya uzantısı: {dosya_yolu.suffix}")
print(f"Ana adı (uzantısız): {dosya_yolu.stem}")

pathlib modülü, dosya ve dizinlerle ilgili birçok işlemi (oluşturma, silme, taşıma, kopyalama) çok daha okunabilir ve güvenli bir şekilde yapmanızı sağlar. Özellikle platformlar arası uyumluluk konusunda os.path'e göre daha modern ve sezgisel bir yaklaşımdır.

Daha Spesifik Hata Yakalama Stratejileri

Önceki bölümde genel Exception yakalamanın genellikle önerilmediğinden bahsetmiştik. Bunun nedeni, programcının öngörmediği veya kontrol edemediği hataları da yakalayarak, programın beklenmedik şekillerde davranmasına yol açabilmesidir. En iyi uygulama, mümkün olduğunca spesifik hataları yakalamak ve genel Exception'ı sadece son çare olarak veya loglama amacıyla kullanmaktır.


def islem_yap(deger):
    try:
        sonuc = 100 / int(deger)
        if sonuc < 0:
            raise ValueError("Sonuç negatif olamaz!") # Özel bir hata firlatma
        return sonuc
    except ValueError as ve:
        print(f"Değer Hatası: {ve} Lütfen pozitif bir sayı girin.")
    except ZeroDivisionError:
        print("Sıfıra bölme hatası! Lütfen sıfır dışında bir sayı girin.")
    except TypeError:
        print("Tip Hatası: Geçersiz veri tipi. Sayısal bir değer bekleniyor.")
    except Exception as e:
        # Bu, yakalayamadığımız diğer tüm hatalar içindir.
        # Loglama yapmak veya programı güvenli bir şekilde kapatmak için idealdir.
        print(f"Beklenmeyen bir hata oluştu: {e}")
    finally:
        print("İşlem denemesi tamamlandı.")

islem_yap("abc") # TypeError veya ValueError
islem_yap("0")   # ZeroDivisionError
islem_yap("10")  # Başarılı
islem_yap("-5")  # ValueError (kendi tanımladığımız hata)

Bu örnekte, TypeError, ValueError ve ZeroDivisionError gibi belirli hata türlerini ayrı ayrı yakalıyoruz. Ayrıca, raise anahtar kelimesiyle kendi özel ValueError hatamızı fırlatarak programın akışını kontrol edebiliyoruz. Bu yaklaşım, hataların nedenlerini daha net anlamamızı ve programımızı daha robust hale getirmemizi sağlar.

Uzman İpucu: Performans Optimizasyonu: Büyük dosyalarla çalışırken read() yerine for satir in dosya: döngüsünü kullanmak veya readlines()'dan kaçınmak, belleği daha verimli kullanmanızı sağlar. Özellikle gigabaytlarca boyuttaki dosyalar için bu çok kritik bir fark yaratabilir, çünkü tüm dosyayı belleğe yüklemek yerine satır satır işlersiniz.

Sonuç: Python Temelleriyle Güçlü Uygulamalar İnşa Edin

Python temel programcılık serimizin dokuzuncu gününde, dosya işlemleri ve hata yönetimi gibi iki hayati konuya odaklandık. Artık programlarınızın sadece anlık verilerle değil, kalıcı depolama birimlerindeki verilerle nasıl etkileşime gireceğini biliyorsunuz. Dosya okuma, yazma ve ekleme modları ile verilerinizi disk üzerinde nasıl yöneteceğinizi, with open(...) yapısının güvenliğini ve pathlib modülünün modern yaklaşımlarını öğrendiniz.

Dahası, programlarınızın beklenmedik durumlara karşı nasıl sağlam ve dayanıklı hale getirileceğini, try-except-else-finally blokları ile hataları nasıl zarifçe yöneteceğinizi kavradınız. Özelleştirilmiş hata yakalama stratejileri ve kendi hatalarınızı fırlatma yeteneği, uygulamalarınızın sadece çalışmasını değil, aynı zamanda güvenilir ve kullanıcı dostu olmasını da sağlar. Son olarak, modüller ve paketler aracılığıyla kodunuzu nasıl organize edeceğinizi, büyük projelerde bile okunabilir ve sürdürülebilir bir yapı nasıl oluşturulacağını gördünüz. Bu temel Python becerileri, her seviyeden programcı için vazgeçilmezdir.

Bu konulara hakim olmak, sizi sadece "kod yazan" birinden "sağlam, güvenilir ve bakımı kolay yazılımlar üreten" bir programcıya dönüştürecektir. Unutmayın, iyi bir program sadece işini yapmakla kalmaz, aynı zamanda hatalarla da başa çıkabilir ve düzenli bir yapıya sahip olur. Bu bilgileri pratik yaparak pekiştirin ve Python yolculuğunuzda bir sonraki adımlara güvenle ilerleyin. Python öğreniminizde yeni yetkinlikler kazanmak için sürekli pratik yapın ve örnek projeler geliştirin. Bu adımlar, Python'ın sunduğu zengin ekosistemden tam olarak yararlanmanızı sağlayacaktır.

Sıkça Sorulan Sorular (SSS)

1. Python'da dosyayı with open(...) kullanmadan açıp kapatırsam ne olur?

Cevap: Dosyayı open() ile açıp close() ile kapatmayı unutursanız, dosya kaynakları program tarafından serbest bırakılmaz. Bu durum, özellikle çok sayıda dosya işlemi yapıldığında kaynak sızıntılarına yol açabilir. İşletim sistemi, dosyanın kullanımda olduğunu düşündüğü için başka programların o dosyaya erişmesini engelleyebilir veya dosya verilerinin bozulmasına neden olabilir. with open(...) yapısı, dosya işlemleri tamamlandığında veya bir hata oluştuğunda dosyayı otomatik olarak ve güvenli bir şekilde kapatır, bu yüzden her zaman tercih edilmelidir.

2. Hata yönetiminde genel except Exception as e: kullanmak neden iyi bir uygulama değildir?

Cevap: Genel except Exception as e: bloğu, yakalanması öngörülen hataların yanı sıra, programcının öngörmediği veya ele almayı planlamadığı tüm diğer hataları da yakalar. Bu durum, ciddi mantık hatalarının veya güvenlik açıklarının maskelenmesine neden olabilir, çünkü program hata oluşmasına rağmen beklenenden farklı bir şekilde çalışmaya devam eder. En iyi uygulama, mümkün olduğunca spesifik hata türlerini yakalamak ve yalnızca çok özel durumlarda veya son çare olarak genel Exception'ı kullanmaktır, genellikle sadece hatayı loglamak veya programı kontrollü bir şekilde sonlandırmak için.

3. __init__.py dosyası bir Python paketinde ne işe yarar?

Cevap: __init__.py dosyası, bir dizinin bir Python paketi olarak kabul edilmesini sağlar. Python yorumlayıcısı, içinde __init__.py bulunan bir dizini bir paket olarak tanır. Bu dosya boş olabilir, ancak genellikle paket ilk kez içe aktarıldığında çalıştırılacak başlatma kodlarını (örneğin, paket seviyesinde değişkenleri tanımlamak veya belirli alt modülleri otomatik olarak içe aktarmak) içerebilir. Python 3.3 ve sonrasında bu dosya teknik olarak zorunlu olmasa da, bir dizinin açıkça bir paket olduğunu belirtmek ve pakete özgü başlatma kodlarını barındırmak için hala yaygın olarak kullanılır ve iyi bir uygulamadır.

4. pathlib modülü mü, yoksa os.path modülü mü kullanmalıyım?

Cevap: Genel olarak, modern Python projeleri için pathlib modülü tercih edilmelidir. pathlib, dosya yollarını nesne yönelimli bir yaklaşımla temsil eder ve dosya sistemi işlemleri için daha sezgisel, temiz ve Pythonic bir API sunar. os.path ise daha eski ve string tabanlı bir yaklaşıma sahiptir. pathlib, platformlar arası uyumluluk konusunda da daha sorunsuz çalışır. Ancak, eski kod tabanlarını korurken veya çok özel durumlar için os.path'a ihtiyaç duyulabilir. Yeni projelerde her zaman pathlib ile başlamak iyi bir alışkanlıktır.

Yorumlar
İçeriği beğendiniz mi? Bir tartışma başlatın veya görüşlerinizi paylaşın.
Yorum Yaz

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

E-posta Bülteni
Yazılım Topluluğuna Katılın
En son güncellemeleri, yaratıcı ipuçlarını ve özel kaynakları doğrudan e-posta kutunuza alın. Tasarım ve inovasyonun geleceğini birlikte keşfedelim.